Railway Operation Simulator  v2.18.0
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 #include <windows.h>
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "TrainUnit.h"
45 #include "GraphicUnit.h"
46 //#include "DisplayUnit.h" included in TrackUnit.h
47 #include "TextUnit.h"
48 #include "PerfLogUnit.h"
49 #include "Utilities.h"
50 
51 #pragma package(smart_init)
52 // ---------------------------------------------------------------------------
53 
56 
57 // ---------------------------------------------------------------------------
58 
59 // FIXED TRACK :-
60 
61 // Constructor to build TrackPieces from array
62 
63 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
64  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
65 {
66  for(int x = 0; x < 4; x++)
67  {
68  Link[x] = LkVal[x];
69  Config[x] = ConfigVal[x];
70  }
71 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
72  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
73  if(SpeedTagVal == 76)
74  {
76  }
77  else if(SpeedTagVal == 77)
78  {
80  }
81  else if(SpeedTagVal == 78)
82  {
84  }
85  else if(SpeedTagVal == 79)
86  {
88  }
89  else if(SpeedTagVal == 96)
90  {
92  }
93  else if(SpeedTagVal == 129)
94  {
96  }
97  else if(SpeedTagVal == 130)
98  {
100  }
101  else if(SpeedTagVal == 131)
102  {
104  }
105  else if(SpeedTagVal == 145)
106  {
108  }
109  else if(SpeedTagVal == 146)
110  {
112  }
113 }
114 
115 // ---------------------------------------------------------------------------
116 
117 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
118  FixedNamedLocationElement(false) // default values
119 {
120  for(int x = 0; x < 4; x++)
121  {
122  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
123  Config[x] = NotSet;
124  }
125 }
126 
127 // ---------------------------------------------------------------------------
128 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
129 {
130  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
131  AnsiString(VLocInput));
132  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
133  Utilities->CallLogPop(1331);
134 }
135 
136 // ---------------------------------------------------------------------------
137 
138 // VARIABLE TRACK :-
139 
140 // ---------------------------------------------------------------------------
141 
143 {
144  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
145  {
146  return(true);
147  }
148  else
149  {
150  return(false);
151  }
152 }
153 
154 // ---------------------------------------------------------------------------
155 
157 {
158  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
159  {
160  return(true);
161  }
162  else
163  {
164  return(false);
165  }
166 }
167 
168 // ---------------------------------------------------------------------------
169 
171 // 'Variable' in the sense that element might be striped or non-striped
172 {
173  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
174  Graphics::TBitmap *GraphicOutput = GraphicPtr;
175 
176  if(LocationName == "")
177  {
178  switch(SpeedTag)
179  {
180  case 76: // t platform
181  GraphicOutput = RailGraphics->gl76Striped;
182  break;
183 
184  case 77: // h platform
185  GraphicOutput = RailGraphics->bm77Striped;
186  break;
187 
188  case 78: // v platform
189  GraphicOutput = RailGraphics->bm78Striped;
190  break;
191 
192  case 79: // r platform
193  GraphicOutput = RailGraphics->gl79Striped;
194  break;
195 
196  case 96: // concourse
197  GraphicOutput = RailGraphics->ConcourseStriped;
198  break;
199 
200  case 129: // v footbridge
201  GraphicOutput = RailGraphics->gl129Striped;
202  break;
203 
204  case 130: // h footbridge
205  GraphicOutput = RailGraphics->gl130Striped;
206  break;
207 
208  case 131: // non-station named loc
209  GraphicOutput = RailGraphics->bmNameStriped;
210  break;
211 
212  case 145: // v underpass
213  GraphicOutput = RailGraphics->gl145Striped;
214  break;
215 
216  case 146: // h underpass
217  GraphicOutput = RailGraphics->gl146Striped;
218  break;
219 
220  default:
221  GraphicOutput = GraphicPtr;
222  break;
223  }
224  }
225  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
226  //deal with TSRs
227  if((TrackType == Simple) && Failed) //added at v2.13.0
228  {
229  Disp->GetImage()->Canvas->Draw((HLoc - Display->DisplayOffsetH) * 16, (VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
230  }
231  Utilities->CallLogPop(1332);
232 }
233 
234 // ---------------------------------------------------------------------------
235 
236 AnsiString TTrackElement::LogTrack(int Caller) const
237 // for debugging when passes as a call parameter
238 {
239  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
240  AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit23) + ",EndTrkEl,";
241 
242  return(LogString);
243 }
244 
245 // ---------------------------------------------------------------------------
246 
248  TTrackElement::TTrackElement(TFixedTrackPiece Input) : TFixedTrackPiece(Input), HLoc(-2000000000), VLoc(-2000000000), LocationName(""), ActiveTrackElementName(""),
249  Attribute(0), CallingOnSet(false), Length01(Utilities->DefaultTrackLength), Length23(-1), SpeedLimit01(Utilities->DefaultTrackSpeedLimit), SpeedLimit23(-1),
250  TrainIDOnElement(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit01(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit23(-1), StationEntryStopLinkPos1(-1),
251  StationEntryStopLinkPos2(-1), StationEntryStopLinkPos3(-1), StationEntryStopLinkPos4(-1), SigAspect(FourAspect)
252  {
253  Failed = false; //added at v2.13.0
254  for(int x = 0; x < 4; x++)
255  {
256  ConnLinkPos[x] = -1;
257  Conn[x] = -1;
258  }
259  if((TrackType == Points) || (TrackType == Crossover) || (TrackType == Bridge))
260  {
263  }
264  }
265 
266 // ---------------------------------------------------------------------------
267 
268 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
269 {
270  if(lower.second < higher.second)
271  {
272  return(true);
273  }
274  else if(lower.second > higher.second)
275  {
276  return(false);
277  }
278  else if(lower.second == higher.second)
279  {
280  if(lower.first < higher.first)
281  {
282  return(true);
283  }
284  }
285  return(false);
286 }
287 
288 // ---------------------------------------------------------------------------
289 // PrefDirElement Functions
290 // ---------------------------------------------------------------------------
291 
292 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
293  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
294  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
295 {
296  if(!EntryExitNumber())
297  {
298  throw Exception("EXNumber failure in TPrefDirElement constructor");
299  }
302 }
303 
304 // ---------------------------------------------------------------------------
305 
306 AnsiString TPrefDirElement::LogPrefDir() const
307 // for debugging when passed as a call parameter
308 {
309  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
310  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
311  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," +
313 
314 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
315  return(LogString);
316 }
317 
318 // ---------------------------------------------------------------------------
319 
320 bool TPrefDirElement::EntryExitNumber() // true for valid number
321 /*
322  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
323  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
324  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
325  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
326  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
327  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
328  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
329  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
330  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
331 */
332 
333 {
334  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
335  int EXArray[16][2] =
336  {{4, 6}, {2, 8}, // horizontal & vertical
337  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
338  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
339  {1, 9}, {3, 7}}; // forward & reverse diagonals
340 
341  int EXNum = -1;
342  int Entry, Exit;
343 
344  if(ELink > -1)
345  {
346  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
347  }
348  else if(Link[2] == -1)
349  {
350  Entry = Link[0];
351  }
352  else
353  {
354  Utilities->CallLogPop(122);
355  return(false);
356  }
357  if(XLink > -1)
358  {
359  Exit = XLink;
360  }
361  else if(Link[2] == -1)
362  {
363  Exit = Link[1];
364  }
365  else
366  {
367  Utilities->CallLogPop(123);
368  return(false);
369  }
370  for(int x = 0; x < 16; x++)
371  {
372  if(((Entry == EXArray[x][0]) && (Exit == EXArray[x][1])) || ((Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))) //added extra brackets round && segments at v2.9.1
373  {
374  EXNum = x;
375  }
376  }
377  if(EXNum == -1)
378  {
379  Utilities->CallLogPop(124);
380  return(false);
381  }
382  int BrNum = -1;
383 
384 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
385  the graphic for each of which is different because of the shape of the overbridge. The basic
386  entry/exit value is computed above, and this used to select only from elements with that entry/exit
387  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
388  int BrEXArray[24][2] = {
389  {4,6},{2,8},{1,9},{3,7},
390  {1,9},{3,7},{1,9},{3,7},
391  {2,8},{4,6},{2,8},{4,6}
392 */
393 
394  if(TrackType == Bridge)
395  {
396  if(EXNum == 1)
397  {
398  if(SpeedTag == 49)
399  {
400  BrNum = 1 + 16;
401  }
402  else if(SpeedTag == 54)
403  {
404  BrNum = 8 + 16;
405  }
406  else if(SpeedTag == 55)
407  {
408  BrNum = 10 + 16;
409  }
410  }
411  else if(EXNum == 0)
412  {
413  if(SpeedTag == 48)
414  {
415  BrNum = 0 + 16;
416  }
417  else if(SpeedTag == 58)
418  {
419  BrNum = 11 + 16;
420  }
421  else if(SpeedTag == 59)
422  {
423  BrNum = 9 + 16;
424  }
425  }
426  else if(EXNum == 14)
427  {
428  if(SpeedTag == 50)
429  {
430  BrNum = 2 + 16;
431  }
432  else if(SpeedTag == 52)
433  {
434  BrNum = 4 + 16;
435  }
436  else if(SpeedTag == 57)
437  {
438  BrNum = 6 + 16;
439  }
440  }
441  else if(EXNum == 15)
442  {
443  if(SpeedTag == 51)
444  {
445  BrNum = 3 + 16;
446  }
447  else if(SpeedTag == 53)
448  {
449  BrNum = 7 + 16;
450  }
451  else if(SpeedTag == 56)
452  {
453  BrNum = 5 + 16;
454  }
455  }
456  }
457  if(BrNum == -1)
458  {
459  EXNumber = EXNum;
460  }
461  else
462  {
463  EXNumber = BrNum;
464  }
465  Utilities->CallLogPop(125);
466  return(true);
467 }
468 
469 // ---------------------------------------------------------------------------
470 
472 /*
473  This is the basic track graphic for use in plotting the original graphic during route flashing.
474  Enter with all set apart from EXGraphic & EntryDirectionGraphic
475 */
476 {
477  if(SpeedTag == 64)
478  {
479  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
480 
481  }
482  if(SpeedTag == 65)
483  {
484  return(RailGraphics->LinkGraphicsPtr[17]);
485  }
486  if(SpeedTag == 66)
487  {
488  return(RailGraphics->LinkGraphicsPtr[18]);
489  }
490  if(SpeedTag == 67)
491  {
492  return(RailGraphics->LinkGraphicsPtr[19]);
493  }
494  if(SpeedTag == 80)
495  {
496  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
497 
498  }
499  if(SpeedTag == 81)
500  {
501  return(RailGraphics->LinkGraphicsPtr[21]);
502  }
503  if(SpeedTag == 82)
504  {
505  return(RailGraphics->LinkGraphicsPtr[22]);
506  }
507  if(SpeedTag == 83)
508  {
509  return(RailGraphics->LinkGraphicsPtr[23]);
510  }
511  if(SpeedTag == 84)
512  {
513  return(RailGraphics->LinkGraphicsPtr[24]);
514  }
515  if(SpeedTag == 85)
516  {
517  return(RailGraphics->LinkGraphicsPtr[25]);
518  }
519  if(SpeedTag == 86)
520  {
521  return(RailGraphics->LinkGraphicsPtr[26]);
522  }
523  if(SpeedTag == 87)
524  {
525  return(RailGraphics->LinkGraphicsPtr[27]);
526  }
527  if(SpeedTag == 129)
528  {
529  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
530 
531  }
532  if(SpeedTag == 130)
533  {
534  return(RailGraphics->LinkGraphicsPtr[29]);
535  }
536  if(XLinkPos == -1) // not set, could be first element or last element = leading point
537  {
538 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
539 // Points & don't want to display these)
540  if(Link[2] != -1)
541  {
542  return(0); // i.e. complex element, don't display
543  }
544  else
545  {
546  if(!EntryExitNumber())
547  {
548  throw Exception("Error in EntryExitNumber 4");
549  }
550  else
551  {
553  }
554  }
555  }
556  if(EXNumber > 15) // underbridge
557  {
558  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
559  }
560  else
561  {
563  }
564 }
565 
566 // ---------------------------------------------------------------------------
567 
569 /*
570  As above but for PrefDir graphics.
571 */
572 {
573  if(SpeedTag == 64)
574  {
575  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
576 
577  }
578  if(SpeedTag == 65)
579  {
581  }
582  if(SpeedTag == 66)
583  {
585  }
586  if(SpeedTag == 67)
587  {
589  }
590  if(SpeedTag == 80)
591  {
592  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
593 
594  }
595  if(SpeedTag == 81)
596  {
598  }
599  if(SpeedTag == 82)
600  {
602  }
603  if(SpeedTag == 83)
604  {
606  }
607  if(SpeedTag == 84)
608  {
610  }
611  if(SpeedTag == 85)
612  {
614  }
615  if(SpeedTag == 86)
616  {
618  }
619  if(SpeedTag == 87)
620  {
622  }
623  if(SpeedTag == 129)
624  {
625  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
626 
627  }
628  if(SpeedTag == 130)
629  {
631  }
632  if(XLinkPos == -1) // not set, could be first element or last element = leading point
633  {
634 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
635  if(Link[2] != -1)
636  {
637  return(0); // i.e. complex element, don't display
638  }
639  else
640  {
641  if(!EntryExitNumber())
642  {
643  throw Exception("Error in EntryExitNumber 5");
644  }
645  else
646  {
648  }
649  }
650  }
651  if(EXNumber > 15) // underbridge
652  {
654  }
655  else
656  {
658  }
659 }
660 
661 // ---------------------------------------------------------------------------
662 
663 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
664 /*
665  As above but for route graphics.
666 */
667 {
668  if(!AutoSigsFlag && !PrefDirRoute)
669  {
670  if(SpeedTag == 64)
671  {
672  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
673  }
674  if(SpeedTag == 65)
675  {
677  }
678  if(SpeedTag == 66)
679  {
681  }
682  if(SpeedTag == 67)
683  {
685  }
686  if(SpeedTag == 80)
687  {
688  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
689  }
690  if(SpeedTag == 81)
691  {
693  }
694  if(SpeedTag == 82)
695  {
697  }
698  if(SpeedTag == 83)
699  {
701  }
702  if(SpeedTag == 84)
703  {
705  }
706  if(SpeedTag == 85)
707  {
709  }
710  if(SpeedTag == 86)
711  {
713  }
714  if(SpeedTag == 87)
715  {
717  }
718  if(SpeedTag == 129)
719  {
720  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
721  }
722  if(SpeedTag == 130)
723  {
725  }
726  if(XLinkPos == -1) // not set, could be first element or last element = leading point
727  {
728  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
729  if(Link[2] != -1)
730  {
731  return(0); // i.e. complex element, don't display
732  }
733  else
734  {
735  if(!EntryExitNumber())
736  {
737  throw Exception("Error in EntryExitNumber 6");
738  }
739  else
740  {
742  }
743  }
744  }
745  if(EXNumber > 15) // underbridge
746  {
748  }
749  else
750  {
752  }
753  }
754 
755  else if(!AutoSigsFlag && PrefDirRoute)
756  {
757  if(SpeedTag == 64)
758  {
759  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
760  }
761  if(SpeedTag == 65)
762  {
764  }
765  if(SpeedTag == 66)
766  {
768  }
769  if(SpeedTag == 67)
770  {
772  }
773  if(SpeedTag == 80)
774  {
775  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
776  }
777  if(SpeedTag == 81)
778  {
780  }
781  if(SpeedTag == 82)
782  {
784  }
785  if(SpeedTag == 83)
786  {
788  }
789  if(SpeedTag == 84)
790  {
792  }
793  if(SpeedTag == 85)
794  {
796  }
797  if(SpeedTag == 86)
798  {
800  }
801  if(SpeedTag == 87)
802  {
804  }
805  if(SpeedTag == 129)
806  {
807  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
808  }
809  if(SpeedTag == 130)
810  {
812  }
813  if(XLinkPos == -1) // not set, could be first element or last element = leading point
814  {
815  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
816  if(Link[2] != -1)
817  {
818  return(0); // i.e. complex element, don't display
819  }
820  else
821  {
822  if(!EntryExitNumber())
823  {
824  throw Exception("Error in EntryExitNumber 10");
825  }
826  else
827  {
829  }
830  }
831  }
832  if(EXNumber > 15) // underbridge
833  {
835  }
836  else
837  {
839  }
840  }
841 
842  else
843  {
844  if(SpeedTag == 64)
845  {
846  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
847  }
848  if(SpeedTag == 65)
849  {
851  }
852  if(SpeedTag == 66)
853  {
855  }
856  if(SpeedTag == 67)
857  {
859  }
860  if(SpeedTag == 80)
861  {
862  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
863 
864  }
865  if(SpeedTag == 81)
866  {
868  }
869  if(SpeedTag == 82)
870  {
872  }
873  if(SpeedTag == 83)
874  {
876  }
877  if(SpeedTag == 84)
878  {
880  }
881  if(SpeedTag == 85)
882  {
884  }
885  if(SpeedTag == 86)
886  {
888  }
889  if(SpeedTag == 87)
890  {
892  }
893  if(SpeedTag == 129)
894  {
895  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
896 
897  }
898  if(SpeedTag == 130)
899  {
901  }
902  if(XLinkPos == -1) // not set, could be first element or last element = leading point
903  {
904  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
905  if(Link[2] != -1)
906  {
907  return(0); // i.e. complex element, don't display
908  }
909  else
910  {
911  if(!EntryExitNumber())
912  {
913  throw Exception("Error in EntryExitNumber 11");
914  }
915  else
916  {
918  }
919  }
920  }
921  if(EXNumber > 15) // underbridge
922  {
924  }
925  else
926  {
928  }
929  }
930 }
931 
932 // ---------------------------------------------------------------------------
933 
935 /*
936  As above but for route flashing graphics. (Disused - now combined with above)
937 */
938 {
939  if(SpeedTag == 64)
940  {
941  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
942 
943  }
944  if(SpeedTag == 65)
945  {
947  }
948  if(SpeedTag == 66)
949  {
951  }
952  if(SpeedTag == 67)
953  {
955  }
956  if(SpeedTag == 80)
957  {
958  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
959 
960  }
961  if(SpeedTag == 81)
962  {
964  }
965  if(SpeedTag == 82)
966  {
968  }
969  if(SpeedTag == 83)
970  {
972  }
973  if(SpeedTag == 84)
974  {
976  }
977  if(SpeedTag == 85)
978  {
980  }
981  if(SpeedTag == 86)
982  {
984  }
985  if(SpeedTag == 87)
986  {
988  }
989  if(SpeedTag == 129)
990  {
991  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
992 
993  }
994  if(SpeedTag == 130)
995  {
997  }
998  if(XLinkPos == -1) // not set, could be first element or last element = leading point
999  {
1000 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
1001  if(Link[2] != -1)
1002  {
1003  return(0); // i.e. complex element, don't display
1004  }
1005  else
1006  {
1007  if(!EntryExitNumber())
1008  {
1009  throw Exception("Error in EntryExitNumber 7");
1010  }
1011  else
1012  {
1014  }
1015  }
1016  }
1017  if(EXNumber > 15) // underbridge
1018  {
1020  }
1021  else
1022  {
1024  }
1025 }
1026 
1027 // ---------------------------------------------------------------------------
1028 
1030 /*
1031  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1032 */
1033 {
1034  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1035  {
1037  }
1038  else
1039  {
1040  throw Exception("Error in EntryExitNumber 8");
1041  }
1042 }
1043 
1044 // ---------------------------------------------------------------------------
1045 
1046 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1047 /*
1048  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1049 */
1050 {
1051  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1052  {
1053  if(!AutoSigsFlag && !PrefDirRoute)
1054  {
1056  }
1057  else if(!AutoSigsFlag && PrefDirRoute)
1058  {
1060  }
1061  else
1062  {
1064  }
1065  }
1066  else
1067  {
1068  throw Exception("Error in EntryExitNumber 9");
1069  }
1070 }
1071 
1072 // ---------------------------------------------------------------------------
1073 
1075 /*
1076  Set == operator when TrackVectorPosition, ELink & XLink all same
1077 */
1078 {
1079  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1080  {
1081  return(true);
1082  }
1083  else
1084  {
1085  return(false);
1086  }
1087 }
1088 
1089 // ---------------------------------------------------------------------------
1090 
1092 /*
1093  Set != operator when any of TrackVectorPosition, ELink or XLink different
1094 */
1095 {
1096  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1097  {
1098  return(false);
1099  }
1100  else
1101  {
1102  return(true);
1103  }
1104 }
1105 
1106 // ---------------------------------------------------------------------------
1107 
1108 int TPrefDirElement::GetRouteColour(Graphics::TBitmap *EXG)
1109 { //returns 1 for red, 2 for green & 3 for blue , or 0 for no match (i.e. using it other than on a route)
1110  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",GetRouteColour");
1111  if(GetRouteGraphicPtr(0,0) == EXG) //AutoSignals, PrefDirRoute
1112  {
1113  Utilities->CallLogPop(2566);
1114  return(1);
1115  }
1116  if(GetRouteGraphicPtr(0,1) == EXG)
1117  {
1118  Utilities->CallLogPop(2567);
1119  return(2);
1120  }
1121  if(GetRouteGraphicPtr(1,0) == EXG)
1122  {
1123  Utilities->CallLogPop(2568);
1124  return(3);
1125  }
1126  if(GetRouteGraphicPtr(1,1) == EXG)
1127  {
1128  Utilities->CallLogPop(2569);
1129  return(3);
1130  }
1131  Utilities->CallLogPop(2570);
1132  return(0);
1133 }
1134 
1135 // ---------------------------------------------------------------------------
1136 // Track functions
1137 // ---------------------------------------------------------------------------
1138 
1139 // ---------------------------------------------------------------------------
1140 
1142 {
1143  TypeOfRoute = 0;
1144  ReducedTimePenalty = false;
1145  BarrierState = Up;
1146  ChangeDuration = 0.0;
1147  BaseElementSpeedTag = 1;
1148  HLoc = 0;
1149  VLoc = 0;
1150  StartTime = TDateTime(0);
1151 }
1152 
1153 // ---------------------------------------------------------------------------
1154 
1156 {
1157 // CurrentSpeedButtonTag = 0; //not assigned yet
1158 
1159  HLocMin = 2000000000;
1160  VLocMin = 2000000000;
1161  HLocMax = -2000000000;
1162  VLocMax = -2000000000;
1163  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1164  CopyFlag = false; // only true for copying, so names aren't copied
1165  AnsiString NL = '\n';
1166 
1167  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable, perhaps because of failed points; " + NL + NL +
1168  "reachable but too far ahead or with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1169  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1170  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1171 
1176 
1177  int InternalLinkCheckArray[9][2] =
1178  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1179 
1180 /* array of valid link values for 'old' location and 'new' location, where
1181  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1182 
1183  for(int x = 0; x < 9; x++)
1184  {
1185  for(int y = 0; y < 2; y++)
1186  {
1187  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1188  }
1189  }
1190 
1191 // Platform and default track element values
1192  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1193 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1194  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1195  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1196  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1197  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10 << 11 << 12 << 13 << 14 << 15 << 16 << 18 << 19 << 20 << 21 << 22 << 23 << 24
1198  << 25 << 26 << 27 << 28 << 29 << 30 << 31 << 32 << 33 << 34 << 35 << 36 << 37 << 38 << 39 << 40 << 41 << 42 << 43 << 44 << 45 << 46 << 47
1199  << 60 << 61 << 62 << 63 << 64 << 65 << 66 << 67 << 68 << 69 << 70 << 71 << 72 << 73 << 74 << 75 << 80 << 81 << 82 << 83 << 84 << 85 << 86
1200  << 87 << 125 << 126 << 127 << 128 << 132 << 133 << 134 << 135 << 136 << 137 << 138 << 139
1201  << 140 << 141 << 142 << 143; //prevent bridges, footcrossings, platforms, concourses, non-station named locs, parapets, level crossings & gaps
1202  //gaps cause a mass of problems as links not adjacent - interferes with cut/copy/paste & duplicate names found
1203  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1204 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1205 
1206  int HVArray[10][2] =
1207  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1208 
1209  for(int x = 0; x < 10; x++)
1210  {
1211  for(int y = 0; y < 2; y++)
1212  {
1213  LinkHVArray[x][y] = HVArray[x][y];
1214  }
1215  }
1216  TrackFinished = false;
1217 // DistancesSet = false;
1218 
1219  TSigElement TempSigTable[40] = // original four aspect
1220  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1221  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1222 
1223  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1224  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1225 
1228 
1229  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1230  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1231 
1232  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1233  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1234  {75, 4, RailGraphics->gl75}};
1235 
1236  for(int x = 0; x < 40; x++)
1237  {
1238  SigTable[x] = TempSigTable[x];
1239  }
1240 
1241  TSigElement TempSigTableThreeAspect[40] =
1242  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1243  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1244 
1245  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1246  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1247 
1248  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1249  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1250 
1251  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1252  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1253 
1254  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1255  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1256  {75, 4, RailGraphics->gl75}};
1257 
1258  for(int x = 0; x < 40; x++)
1259  {
1260  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1261  }
1262 
1263  TSigElement TempSigTableTwoAspect[40] =
1264  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1265  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1266 
1267  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1268  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1269 
1270  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1271  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1272 
1273  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1274  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1275 
1276  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1277  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1278  {75, 4, RailGraphics->gl75}};
1279 
1280  for(int x = 0; x < 40; x++)
1281  {
1282  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1283  }
1284 
1285  TSigElement TempSigTableGroundSignal[40] =
1289 
1293 
1297 
1301 
1302  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1305 
1306  for(int x = 0; x < 40; x++)
1307  {
1308  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1309  }
1310 
1311  TSigElement TempFailedSigTable[8] = // added at v2.13.0
1312  {{68, 0, RailGraphics->FSig68}, {69, 0, RailGraphics->FSig69}, {70, 0, RailGraphics->FSig70}, {71, 0, RailGraphics->FSig71}, {72, 0, RailGraphics->FSig72},
1313  {73, 0, RailGraphics->FSig73}, {74, 0, RailGraphics->FSig74}, {75, 0, RailGraphics->FSig75}};
1314 
1315  for(int x = 0; x < 8; x++)
1316  {
1317  FailedSigTable[x] = TempFailedSigTable[x];
1318  }
1319 
1320  TSigElement TempFailedGroundSigTable[8] = // added at v2.14.0 to allow ground signals to fail
1321  {{68, 0, RailGraphics->FGSig68}, {69, 0, RailGraphics->FGSig69}, {70, 0, RailGraphics->FGSig70}, {71, 0, RailGraphics->FGSig71}, {72, 0, RailGraphics->FGSig72},
1322  {73, 0, RailGraphics->FGSig73}, {74, 0, RailGraphics->FGSig74}, {75, 0, RailGraphics->FGSig75}};
1323 
1324  for(int x = 0; x < 8; x++)
1325  {
1326  FailedGroundSigTable[x] = TempFailedGroundSigTable[x];
1327  }
1328 
1329 /*
1330  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1331  a single location. These are as follows:-
1332  Directly Adjacent = up, down, left or right - NOT diagonal.
1333  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1334  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1335  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1336 
1337  //t 76
1338  //b 77
1339  //l 78
1340  //r 79
1341  //c 96
1342  //v fb 129
1343  //h fb 130
1344  //v underpass 145
1345  //h underpass 146
1346  //n 131
1347 */
1348 
1349  int Tag76[25][3] =
1350  {{-1, 0, 96}, // c top plat
1351  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1352  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1353  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1354  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1355  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1356  {0, 0, 129}, {0, -1, 145}, // v up
1357  {0, 0, 145}};
1358 
1359  for(int x = 0; x < 25; x++)
1360  {
1361  for(int y = 0; y < 3; y++)
1362  {
1363  Tag76Array[x][y] = Tag76[x][y];
1364  }
1365  }
1366 
1367  int Tag77[25][3] =
1368  {{-1, 0, 96}, // c bot plat
1369  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1370  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1371  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1372  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1373  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1374  {0, 0, 129}, {0, 1, 145}, // v up
1375  {0, 0, 145}};
1376 
1377  for(int x = 0; x < 25; x++)
1378  {
1379  for(int y = 0; y < 3; y++)
1380  {
1381  Tag77Array[x][y] = Tag77[x][y];
1382  }
1383  }
1384 
1385  int Tag78[25][3] =
1386  {{-1, 0, 96}, // c left plat
1387  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1388  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1389  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1390  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1391  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1392  {0, 0, 130}, {-1, 0, 146}, // h up
1393  {0, 0, 146}};
1394 
1395  for(int x = 0; x < 25; x++)
1396  {
1397  for(int y = 0; y < 3; y++)
1398  {
1399  Tag78Array[x][y] = Tag78[x][y];
1400  }
1401  }
1402 
1403  int Tag79[25][3] =
1404  {{-1, 0, 96}, // c right plat
1405  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1406  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1407  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1408  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1409  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1410  {0, 0, 130}, {1, 0, 146}, // h up
1411  {0, 0, 146}};
1412 
1413  for(int x = 0; x < 25; x++)
1414  {
1415  for(int y = 0; y < 3; y++)
1416  {
1417  Tag79Array[x][y] = Tag79[x][y];
1418  }
1419  }
1420 
1421  int Tag96[28][3] =
1422  {{-1, 0, 96}, // c //concourse
1423  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1424  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1425  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1426  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1427  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1428  {0, -1, 129}, {1, 0, 130}, // h fb
1429  {-1, 0, 130}, {0, 1, 145}, // v up
1430  {0, -1, 145}, {1, 0, 146}, // h up
1431  {-1, 0, 146}};
1432 
1433  for(int x = 0; x < 28; x++)
1434  {
1435  for(int y = 0; y < 3; y++)
1436  {
1437  Tag96Array[x][y] = Tag96[x][y];
1438  }
1439  }
1440 
1441  int Tag129[8][3] = // vert fb
1442  {{0, -1, 96}, // c
1443  {0, -1, 77}, // b
1444  {0, -1, 129}, // v fb
1445 
1446  {0, 1, 96}, // c
1447  {0, 1, 76}, // t
1448  {0, 1, 129}, // v fb
1449 
1450  {0, 0, 76}, // t
1451  {0, 0, 77}}; // b
1452 
1453  for(int x = 0; x < 8; x++)
1454  {
1455  for(int y = 0; y < 3; y++)
1456  {
1457  Tag129Array[x][y] = Tag129[x][y];
1458  }
1459  }
1460 
1461  int Tag145[8][3] = // vert up
1462  {{0, -1, 96}, // c
1463  {0, -1, 77}, // b
1464  {0, -1, 145}, // v fb
1465 
1466  {0, 1, 96}, // c
1467  {0, 1, 76}, // t
1468  {0, 1, 145}, // v fb
1469 
1470  {0, 0, 76}, // t
1471  {0, 0, 77}}; // b
1472 
1473  for(int x = 0; x < 8; x++)
1474  {
1475  for(int y = 0; y < 3; y++)
1476  {
1477  Tag145Array[x][y] = Tag145[x][y];
1478  }
1479  }
1480 
1481  int Tag130[8][3] = // hor fb
1482  {{-1, 0, 96}, // c
1483  {-1, 0, 79}, // r
1484  {-1, 0, 130}, // h fb
1485 
1486  {1, 0, 96}, // c
1487  {1, 0, 78}, // l
1488  {1, 0, 130}, // h fb
1489 
1490  {0, 0, 78}, // l
1491  {0, 0, 79}}; // r
1492 
1493  for(int x = 0; x < 8; x++)
1494  {
1495  for(int y = 0; y < 3; y++)
1496  {
1497  Tag130Array[x][y] = Tag130[x][y];
1498  }
1499  }
1500 
1501  int Tag146[8][3] = // hor up
1502  {{-1, 0, 96}, // c
1503  {-1, 0, 79}, // r
1504  {-1, 0, 146}, // h fb
1505 
1506  {1, 0, 96}, // c
1507  {1, 0, 78}, // l
1508  {1, 0, 146}, // h fb
1509 
1510  {0, 0, 78}, // l
1511  {0, 0, 79}}; // r
1512 
1513  for(int x = 0; x < 8; x++)
1514  {
1515  for(int y = 0; y < 3; y++)
1516  {
1517  Tag146Array[x][y] = Tag146[x][y];
1518  }
1519  }
1520 
1521  int Tag131[4][3] =
1522  {{-1, 0, 131}, // n
1523  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1524 
1525  for(int x = 0; x < 4; x++)
1526  {
1527  for(int y = 0; y < 3; y++)
1528  {
1529  Tag131Array[x][y] = Tag131[x][y];
1530  }
1531  }
1532 
1533  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1534  {
1535  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1536  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1537  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1538  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1539  140, 144, 145, 146
1540  };
1541 
1542  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1543  {
1544  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1545  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1546  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1547  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1548  141, 144, 145, 146
1549  };
1550 
1551  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1552  {
1553  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1554  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1555  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1556  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1557  141, 144, 146, 145
1558  };
1559 
1560  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1561  {
1562  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1563  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1564  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1565  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1566  140, 144, 146, 145
1567  };
1568 
1569  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1570  {
1571  FlipArray[x] = InternalFlipArray[x];
1572  MirrorArray[x] = InternalMirrorArray[x];
1573  RotRightArray[x] = InternalRotRightArray[x];
1574  RotLeftArray[x] = InternalRotLeftArray[x];
1575  }
1576 }
1577 
1578 // ---------------------------------------------------------------------------
1580 {
1581 // delete TrackVectorPtr;
1582 // delete FixedTrackArrayPtr;
1583  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1584 
1585  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1586  {
1587  delete UGMIt->second;
1588  UGMIt++;
1589  }
1590  delete GapFlashGreen;
1591  delete GapFlashRed;
1592  // all the rest are cleared by the relevant automatic destructors
1593 }
1594 
1595 // ---------------------------------------------------------------------------
1596 
1598 {
1599  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1600  {
1601 // loc 0 not used, set to bmSolidBgnd
1605 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1625  };
1626 
1627  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1628  {
1629 // loc 0 not used, set to smSolidBgnd
1633 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1652  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1653  };
1654 
1655 // track types
1656  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1657  {
1658  Erase, // 1 0
1659  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1660  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1661  Crossover, Crossover, // 2 15-16
1662  Unused, // 17 (was for text in earlier development) //1 17
1665  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1669  Platform, Platform, Platform, Platform, // 4 76-79
1672  Concourse, // 1 96
1675  Simple, Simple, Simple, Simple, // 4 125-128
1676  FootCrossing, FootCrossing, // 2 129-130
1677  NamedNonStationLocation, // 1 131
1678  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1679  Simple, Simple, Simple, Simple, // 4 140-143
1680  LevelCrossing, // 1 144
1681  FootCrossing, FootCrossing // 2 145 & 146
1682  };
1683 
1684 // links
1685  int Links[FirstUnusedSpeedTagNumber][4] =
1686  {{-1, -1, -1, -1}, // erase element
1687  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1688  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1689 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1690  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1691  {-1, -1, -1, -1}, // unused
1692  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1693  {2, 7, -1, -1}, // simple
1694  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1695 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1696 // (or right diverging if no straight)
1697  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1698  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1699  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1700  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1701  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1702  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1703  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1704  {-1, -1, -1, -1}, // Concourse
1705  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1706  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1707  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1708  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1709  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1710  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1711  {-1, -1, -1, -1}, // NamedNonStationLocation
1712  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1713 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1714  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1715  {-1, -1, -1, -1}, // level crossing
1716  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1717  };
1718 
1720  {{NotSet, NotSet, NotSet, NotSet}, // unused
1724  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1726  {NotSet, NotSet, NotSet, NotSet}, // unused
1730  {Connection, Connection, NotSet, NotSet}, // simple
1734  {Lead, Trail, Lead, Trail}, // points
1736  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1744  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1750  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1759  {Connection, Connection, NotSet, NotSet}, // Arrows
1761  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1763  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1765  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1766  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1767  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1768  };
1769 
1770  for(int x = 0; x < 17; x++)
1771  {
1772  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1773  }
1774  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1775 // 17 was the old text value so don't want any graphics (now disused)
1776  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1777  {
1778  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1779  }
1780 }
1781 
1782 // ---------------------------------------------------------------------------
1783 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1784  ExistingGraphicLoaded(false), Width(16), Height(16)
1785 {
1786  OriginalGraphic = new Graphics::TBitmap;
1787  OriginalGraphic->PixelFormat = pf8bit;
1788  OriginalGraphic->Width = Width;
1789  OriginalGraphic->Height = Height;
1790  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1791 }
1792 
1793 // ---------------------------------------------------------------------------
1794 
1795 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1796  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1797 {
1798  OriginalGraphic = new Graphics::TBitmap;
1799  OriginalGraphic->PixelFormat = pf8bit;
1800  OriginalGraphic->Width = Width;
1801  OriginalGraphic->Height = Height;
1802  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1803 }
1804 
1805 // ---------------------------------------------------------------------------
1806 
1808 {
1809  delete OriginalGraphic;
1810 }
1811 
1812 // ---------------------------------------------------------------------------
1813 
1814 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1815 {
1816  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1817  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1818  VPos = VPosIn;
1819  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1820 
1821  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1822  SourceRect.init(Left, Top, Left + Width, Top + Height);
1823  ScreenSourceSet = true;
1824  Utilities->CallLogPop(422);
1825 }
1826 
1827 // ---------------------------------------------------------------------------
1828 
1830 {
1831  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1832  if(!OverlayLoaded)
1833  {
1834  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1835  }
1836  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1837  {
1838  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1839  }
1840  if(!ScreenSourceSet)
1841  {
1842  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1843  }
1844  if(ExistingGraphicLoaded) // can only call one of the load functions
1845  {
1846  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1847  }
1848  if(OverlayPlotted) // don't load from screen if overlay plotted
1849  {
1850  Utilities->CallLogPop(775);
1851  return;
1852  }
1853  TRect DestRect(0, 0, Width, Height);
1854 
1856  OriginalLoaded = true;
1857  ScreenGraphicLoaded = true;
1858  Utilities->CallLogPop(423);
1859 }
1860 
1861 // ---------------------------------------------------------------------------
1862 
1863 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1864 /*
1865  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1866 */
1867 {
1868  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1869  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1870  if(!OverlayLoaded)
1871  {
1872  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1873  }
1874  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1875  {
1876  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1877  }
1878  if(ScreenGraphicLoaded) // can only call one of the load functions
1879  {
1880  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1881  }
1882  Width = WidthIn;
1883  Height = HeightIn;
1884  OriginalGraphic->Width = Width;
1885  OriginalGraphic->Height = Height;
1886  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1887  VPos += VOffset;
1888  TRect DestRect(0, 0, Width, Height);
1889 
1890  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1891  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1892  OriginalLoaded = true;
1893  ExistingGraphicLoaded = true;
1894  Utilities->CallLogPop(424);
1895 }
1896 
1897 // ---------------------------------------------------------------------------
1898 
1899 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1900 {
1901  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1902  OverlayGraphic = Overlay;
1903  OverlayLoaded = true;
1904  Utilities->CallLogPop(425);
1905 }
1906 
1907 // ---------------------------------------------------------------------------
1908 
1910 {
1911  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1912  if(!OverlayLoaded)
1913  {
1914  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1915  }
1916  if(!OverlayPlotted)
1917  {
1918  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1919  Disp->Update();
1920  OverlayPlotted = true;
1921  }
1922  Utilities->CallLogPop(426);
1923 }
1924 
1925 // ---------------------------------------------------------------------------
1926 
1928 {
1929  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1930  if(OverlayPlotted)
1931  {
1932  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1933  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1934  {
1935  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1936  }
1937  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1938  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1939  OverlayPlotted = false;
1940  }
1941  Utilities->CallLogPop(427);
1942 }
1943 
1944 // ---------------------------------------------------------------------------
1945 
1947 {
1948  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1949  bool TrackPresent = false;
1950 
1951  if(InactiveTrackVector.size() != 0)
1952  {
1953  Utilities->CallLogPop(1333);
1954  return(false);
1955  }
1956  else if(TrackVector.size() == 0)
1957  {
1958  Utilities->CallLogPop(1334);
1959  return(true);
1960  }
1961  else
1962  {
1963  for(unsigned int x = 0; x < TrackVector.size(); x++)
1964  {
1965  if((TrackElementAt(1042, x).SpeedTag != 0))
1966  {
1967  TrackPresent = true;
1968  }
1969  }
1970  }
1971  Utilities->CallLogPop(1335);
1972  return(!TrackPresent);
1973 }
1974 
1975 // ---------------------------------------------------------------------------
1976 
1977 bool TTrack::NoActiveTrack(int Caller)
1978 {
1979  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1980  bool TrackPresent = false;
1981 
1982  if(TrackVector.size() == 0)
1983  {
1984  Utilities->CallLogPop(1582);
1985  return(true);
1986  }
1987  else
1988  {
1989  for(unsigned int x = 0; x < TrackVector.size(); x++)
1990  {
1991  if((TrackElementAt(1043, x).SpeedTag != 0))
1992  {
1993  TrackPresent = true;
1994  }
1995  break;
1996  }
1997  }
1998  Utilities->CallLogPop(1583);
1999  return(!TrackPresent);
2000 }
2001 
2002 // ---------------------------------------------------------------------------
2003 
2004 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
2005 {
2006  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
2007  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2008  TrackEraseSuccessfulFlag = false;
2009 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
2010 // since have to match platforms as well as track
2011 // used to set TrackFinished to false if an element erased
2012 
2013  ErasedTrackVectorPosition = -1; // marker for no element erased
2014  AnsiString SName = "", ErrorString;
2016  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
2017  TTrackMapIterator TrackMapPtr;
2018  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
2019 
2020  if(TrackVector.size() != 0)
2021  {
2022  TrackMapKeyPair.first = HLocInput;
2023  TrackMapKeyPair.second = VLocInput;
2024  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
2025  if(TrackMapPtr != TrackMap.end())
2026  {
2027  bool FoundFlag;
2028  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
2029  if(FoundFlag) // should find it as it's in the map
2030  {
2031  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
2032  {
2033  SName = TrackElementAt(1, VecPos).LocationName;
2034  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
2035  if(ErrorString != "")
2036  {
2037  throw Exception(ErrorString + " for EraseTrackElement 1");
2038  }
2039  LocationNameMultiMap.erase(SNIt);
2040  }
2041  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
2042  // ensure erase vector element before map element as iterator no longer valid after a map erase
2043  TrackMap.erase(TrackMapPtr);
2044  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
2045  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2047  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
2048  if(SName != "")
2049  {
2050  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2051  int HPos, VPos;
2052  if(TextHandler->FindText(1, SName, HPos, VPos))
2053  {
2054  if(TextHandler->TextErase(5, HPos, VPos, SName))
2055  {
2056  ;
2057  } // condition not used
2058 
2059  }
2060  }
2061  ErasedTrackVectorPosition = VecPos;
2062  TrackEraseSuccessfulFlag = true;
2063  }
2064  }
2065  }
2066  if(InactiveTrackVector.size() != 0)
2067  {
2068  unsigned int VecPos;
2069  InactiveTrackMapKeyPair.first = HLocInput;
2070  InactiveTrackMapKeyPair.second = VLocInput;
2071  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2072  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2073  {
2074  SName = "";
2075  VecPos = InactiveTrack2MultiMapIterator->second;
2076  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2077  {
2078  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2079  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2080  if(ErrorString != "")
2081  {
2082  throw Exception(ErrorString + " for EraseTrackElement 2A");
2083  }
2084  LocationNameMultiMap.erase(SNIt);
2085  }
2086  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2087  // ensure erase vector element before map element as iterator no longer valid after a map erase
2088  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2089  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2090  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2092  TrackEraseSuccessfulFlag = true;
2093  if(SName != "")
2094  {
2095  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2096  int HPos, VPos;
2097  if(TextHandler->FindText(2, SName, HPos, VPos))
2098  {
2099  if(TextHandler->TextErase(6, HPos, VPos, SName))
2100  {
2101  ;
2102  } // condition not used
2103 
2104  }
2105  }
2106  }
2107  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2108  {
2109  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2110  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2111  {
2112  SName = "";
2113  VecPos = InactiveTrack2MultiMapIterator->second;
2114  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2115  {
2116  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2117  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2118  if(ErrorString != "")
2119  {
2120  throw Exception(ErrorString + " for EraseTrackElement 2B");
2121  }
2122  LocationNameMultiMap.erase(SNIt);
2123  }
2124  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2125  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2126  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2128  if(SName != "")
2129  {
2130  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2131  int HPos, VPos;
2132  if(TextHandler->FindText(3, SName, HPos, VPos))
2133  {
2134  if(TextHandler->TextErase(7, HPos, VPos, SName))
2135  {
2136  ;
2137  } // condition not used
2138 
2139  }
2140  }
2141  }
2142  }
2143  }
2144  if(TrackEraseSuccessfulFlag)
2145  {
2146  CalcHLocMinEtc(2);
2147  SetTrackFinished(false);
2148  }
2149  if(InternalChecks)
2150  {
2151  CheckMapAndTrack(1); // test
2152  CheckMapAndInactiveTrack(1); // test
2153  CheckLocationNameMultiMap(6); // test
2154  }
2155  Utilities->CallLogPop(428);
2156 }
2157 
2158 // ---------------------------------------------------------------------------
2159 
2160 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks, bool PerformNameSearch)
2161 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2162 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2163 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2164 // PerformNameSearch added at v2.18.0 to speed up named element additions when area selected
2165 {
2166  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2167  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2168  bool PlatAllowedFlag = false;
2169 
2170  TrackLinkingRequiredFlag = false;
2171 /*
2172  Not erase, that covered separately.
2173  First check if Current SpeedButton assigned, then check if a platform and only
2174  permit if an appropriate trackpiece already there & not a same platform there.
2175  - can't enter a platform without track first.
2176  Then for non-platforms, check if a track piece already present at location &
2177  reject if so.
2178 */
2179 
2180  TLocationNameMultiMapEntry LocationNameEntry;
2181 
2182  LocationNameEntry.first = "";
2183  if(CurrentTag == 0)
2184  {
2185  Utilities->CallLogPop(429);
2186  return; // not assigned yet
2187  }
2188  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2189 
2190  TempTrackElement.HLoc = HLocInput;
2191  TempTrackElement.VLoc = VLocInput;
2192  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2193 // new at version 0.6 - set signal aspect depending on build mode
2194 
2195  if(TempTrackElement.TrackType == SignalPost)
2196  {
2197  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2198  // pasting a SignalPost can only have values 1 to 4
2199  {
2201  {
2202  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2203  }
2205  {
2206  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2207  }
2209  {
2210  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2211  }
2212  else
2213  {
2214  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2215  }
2216  }
2217  else if(Aspect == 1)
2218  {
2219  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2220  }
2221  else if(Aspect == 2)
2222  {
2223  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2224  }
2225  else if(Aspect == 3)
2226  {
2227  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2228  }
2229  else
2230  {
2231  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2232  }
2233  }
2234  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2235  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2236  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2237  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2238 
2239  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2240  {
2242  {
2243  NonStationOrLevelCrossingPresent = true;
2244  }
2245  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2246  {
2247  NonStationOrLevelCrossingPresent = true;
2248  }
2249  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2250  {
2251  PlatformPresent = true;
2252  }
2253  // no need to check IMPair.second since if that exists it is because .first is a platform
2254  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2255  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2256  }
2257 // check platforms
2258  if(TempTrackElement.TrackType == Platform)
2259  {
2260  if(FoundFlag) // active track element already there
2261  {
2262  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2263  {
2264  ;
2265  }
2266  // same platform type already there so above keeps PlatAllowedFlag false
2267  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1044, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2268  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2269  {
2270  PlatAllowedFlag = true;
2271  }
2272  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1045, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2273  {
2274  PlatAllowedFlag = true;
2275  }
2276  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1046, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2277  {
2278  PlatAllowedFlag = true;
2279  }
2280  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1047, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2281  {
2282  PlatAllowedFlag = true;
2283  }
2284  if(PlatAllowedFlag)
2285  {
2286  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2287  TrackPush(1, TempTrackElement);
2288  if(PerformNameSearch)
2289  {
2290  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2291  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2292  // Must be called AFTER TrackPush
2293  // No need to plot the element - Clearand ... called after this function called
2294  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2295  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2296  }
2297 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2298 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2299 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2300  if(InternalChecks)
2301  {
2302  CheckMapAndInactiveTrack(5); // test
2303  CheckLocationNameMultiMap(4); // test
2304  }
2305  Utilities->CallLogPop(430);
2306  return;
2307  }
2308  } // if(FoundFlag)
2309 
2310  Utilities->CallLogPop(431);
2311  return;
2312  } // if platform
2313 
2314 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2315  if(TempTrackElement.TrackType == NamedNonStationLocation)
2316  {
2317  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1048, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2318  (!FoundFlag && !InactiveFoundFlag))
2319  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2320  {
2321  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2322  TrackPush(2, TempTrackElement);
2323  if(PerformNameSearch)
2324  {
2325  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2326  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2327  }
2328  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2329  {
2330 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2331 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2332 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2333  }
2334  if(InternalChecks)
2335  {
2336  CheckMapAndInactiveTrack(11); // test
2337  CheckLocationNameMultiMap(12); // test
2338  }
2339  Utilities->CallLogPop(432);
2340  return;
2341  }
2342  else
2343  {
2344  Utilities->CallLogPop(433);
2345  return;
2346  }
2347  }
2348 // check if a level crossing - OK if placed on a plain straight track
2349  if(TempTrackElement.TrackType == LevelCrossing)
2350  {
2351  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1049, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2352  {
2353  TrackPush(11, TempTrackElement);
2354  PlotRaisedLinkedLevelCrossingBarriers(0, TrackElementAt(1050, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2355 // no need for reference to LC element as can't be open
2356  TrackLinkingRequiredFlag = true;
2357  Utilities->CallLogPop(1907);
2358  return;
2359  }
2360  else
2361  {
2362  Utilities->CallLogPop(1906);
2363  return; // was a level crossing but can't place it for some reason
2364  }
2365  }
2366 
2367 // check if another element already there
2368  else if(FoundFlag || InactiveFoundFlag)
2369  {
2370  Utilities->CallLogPop(434);
2371  return; // something already there (active or inactive track)
2372  }
2373 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2374 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2375 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2376 // do this after pushed into vector so that can use EnterLocationName
2377 
2378  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2379  {
2380  TrackPush(3, TempTrackElement);
2381  if(PerformNameSearch)
2382  {
2383  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2384  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2385  }
2386  }
2387  else if(TempTrackElement.TrackType == Points)
2388  {
2389  TrackPush(4, TempTrackElement);
2390  bool BothPointFillets = true;
2391  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2392  }
2393  else if(TempTrackElement.TrackType == SignalPost)
2394  {
2395  TrackPush(10, TempTrackElement);
2396  PlotSignal(12, TempTrackElement, Display);
2397  }
2398  else
2399  {
2400  TrackPush(5, TempTrackElement);
2401  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2402  }
2403  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2404  {
2405  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2406  }
2407  if(InternalChecks && PerformNameSearch) //don't carry out checks if PerformNameSearch false else will fail, should be set correctly in calling function but include to be sure
2408  {
2409  CheckMapAndTrack(2); // test
2410  CheckMapAndInactiveTrack(2); // test
2411  CheckLocationNameMultiMap(5); // test
2412  }
2413  Utilities->CallLogPop(2062);
2414 }
2415 
2416 // ---------------------------------------------------------------------------
2417 
2418 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2419  bool InternalChecks)
2420 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2421 {
2422  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2423  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2424  bool PlatAllowedFlag = false;
2425 
2426  TrackLinkingRequiredFlag = false;
2427  TLocationNameMultiMapEntry LocationNameEntry;
2428 
2429  LocationNameEntry.first = "";
2430  if(TempTrackElement.SpeedTag == 0)
2431  {
2432  Utilities->CallLogPop(2063);
2433  return; // not assigned yet
2434  }
2435  TempTrackElement.HLoc = HLocInput;
2436  TempTrackElement.VLoc = VLocInput;
2437  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2438  for(int x = 0; x < 4; x++) // unset any gaps,
2439  {
2440  if(TempTrackElement.Config[x] == Gap)
2441  {
2442  TempTrackElement.ConnLinkPos[x] = -1;
2443  }
2444  TempTrackElement.Conn[x] = -1;
2445  }
2446  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2447 // new at version 0.6 - set signal aspect depending on build mode
2448  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2449 
2450  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2451  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2452  // for the active track element because these aren't set
2453  // if don't do this then get a mismatch error during map checks later
2454 
2455  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2456 
2457  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2458  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2459 
2460  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2461  {
2462  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2463  {
2464  NonStationOrLevelCrossingPresent = true;
2465  }
2466  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2467  {
2468  NonStationOrLevelCrossingPresent = true;
2469  }
2470  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2471  {
2472  PlatformPresent = true;
2473  }
2474  // no need to check IMPair.second since if that exists it is because .first is a platform
2475  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2476  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2477  }
2478 // check platforms
2479  if(TempTrackElement.TrackType == Platform)
2480  {
2481  if(FoundFlag) // active track element already there
2482  {
2483  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2484  {
2485  ;
2486  }
2487  // same platform type already there so above keeps PlatAllowedFlag false
2488  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1051, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2489  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2490  {
2491  PlatAllowedFlag = true;
2492  }
2493  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1052, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2494  {
2495  PlatAllowedFlag = true;
2496  }
2497  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1053, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2498  {
2499  PlatAllowedFlag = true;
2500  }
2501  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1054, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2502  {
2503  PlatAllowedFlag = true;
2504  }
2505  if(PlatAllowedFlag)
2506  {
2507  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2508  TrackPush(12, TempTrackElement);
2509 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2510  {
2511  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2512  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2513  }
2514  // Must be called AFTER TrackPush
2515 // No need to plot the element - Clearand ... called after this function called
2516  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2517  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2518 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2519 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2520 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2521  if(InternalChecks)
2522  {
2523  CheckMapAndInactiveTrack(12); // test
2524  CheckLocationNameMultiMap(20); // test
2525  }
2526  Utilities->CallLogPop(2064);
2527  return;
2528  }
2529  } // if(FoundFlag)
2530 
2531  Utilities->CallLogPop(2065);
2532  return;
2533  } // if platform
2534 
2535 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2536  if(TempTrackElement.TrackType == NamedNonStationLocation)
2537  {
2538  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1055, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2539  (!FoundFlag && !InactiveFoundFlag))
2540  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2541  {
2542  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2543  TrackPush(13, TempTrackElement);
2544 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2545  {
2546  {
2547  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2548  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2549  }
2550  }
2551  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2552  {
2553 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2554 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2555 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2556  }
2557  if(InternalChecks)
2558  {
2559  CheckMapAndInactiveTrack(13); // test
2560  CheckLocationNameMultiMap(21); // test
2561  }
2562  Utilities->CallLogPop(2066);
2563  return;
2564  }
2565  else
2566  {
2567  Utilities->CallLogPop(2067);
2568  return;
2569  }
2570  }
2571 // check if a level crossing - OK if placed on a plain straight track
2572  if(TempTrackElement.TrackType == LevelCrossing)
2573  {
2574  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1056, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2575  {
2576  TrackPush(14, TempTrackElement);
2577  PlotRaisedLinkedLevelCrossingBarriers(3, TrackElementAt(1057, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2578 // no need for reference to LC element as can't be open
2579  TrackLinkingRequiredFlag = true;
2580  Utilities->CallLogPop(2068);
2581  return;
2582  }
2583  else
2584  {
2585  Utilities->CallLogPop(2069);
2586  return; // was a level crossing but can't place it for some reason
2587  }
2588  }
2589 
2590 // check if another element already there
2591  else if(FoundFlag || InactiveFoundFlag)
2592  {
2593  Utilities->CallLogPop(2070);
2594  return; // something already there (active or inactive track)
2595  }
2596 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2597 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2598 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2599 // do this after pushed into vector so that can use EnterLocationName
2600 
2601  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2602  {
2603  TrackPush(15, TempTrackElement);
2604  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2605  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2606  }
2607  else if(TempTrackElement.TrackType == Points)
2608  {
2609  TrackPush(16, TempTrackElement);
2610  bool BothPointFillets = true;
2611  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2612  }
2613  else if(TempTrackElement.TrackType == SignalPost)
2614  {
2615  TrackPush(17, TempTrackElement);
2616  PlotSignal(14, TempTrackElement, Display);
2617  }
2618  else
2619  {
2620  TrackPush(18, TempTrackElement);
2621  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2622  }
2623  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2624  {
2625  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2626  }
2627  if(InternalChecks)
2628  {
2629  CheckMapAndTrack(12); // test
2630  CheckMapAndInactiveTrack(14); // test
2631  CheckLocationNameMultiMap(22); // test
2632  }
2633  Utilities->CallLogPop(2071);
2634 }
2635 
2636 // ---------------------------------------------------------------------------
2637 
2638 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2639 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2640 // return bool = true for success
2641 // LocError = true for location error & HLoc & VLoc to be inverted
2642 {
2643  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2644  LocError = false;
2645  SetTrackFinished(false);
2646  if(TrackVector.size() == 0)
2647  {
2648  Utilities->CallLogPop(437);
2649  return(false);
2650  }
2651  if(GapsUnset(7))
2652  {
2653  if(GiveMessages)
2654  {
2655  ShowMessage("Gaps must be set before track can be validated");
2656  }
2657  Utilities->CallLogPop(1135);
2658  return(false);
2659  }
2660 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2661 // returns true for any unset gaps
2663  {
2664  // can keep this exception as protected by the GapsUnset call above
2665  throw Exception("Error, gaps unset when TryToConnectTrack called");
2666  }
2668  CheckGapMap(1); // test
2669 // Gap connections now securely defined
2670 
2671  CheckMapAndTrack(8); // test
2672 
2673 // Perform a pre-check prior to TrackMap being compiled
2674  if(GiveMessages)
2675  {
2676  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2677  {
2678  Utilities->CallLogPop(439);
2679  return(false);
2680  }
2681  }
2682  else
2683  {
2684  if(!LinkTrackNoMessages(1, false))
2685  {
2686  Utilities->CallLogPop(1131);
2687  return(false);
2688  }
2689  }
2690 // here if pre-check successful
2691  if(!RepositionAndMapTrack(0))
2692  {
2693  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2694  Utilities->CallLogPop(1138);
2695  return(false);
2696  }
2697 // now perform the final assembly - FinalCall = true
2698  if(GiveMessages)
2699  {
2700  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2701  {
2702  Utilities->CallLogPop(1116);
2703  return(false);
2704  }
2705  }
2706  else
2707  {
2708  if(!LinkTrackNoMessages(2, true))
2709  {
2710  Utilities->CallLogPop(1132);
2711  return(false);
2712  }
2713  }
2714 // success
2715 
2716  PopulateLCVector(0);
2717  CheckGapMap(2); // test
2718  CheckMapAndTrack(3); // test
2719  CheckMapAndInactiveTrack(3); // test
2720  CheckLocationNameMultiMap(9); // test
2721  SetTrackFinished(true);
2722 
2723 // Build ContinuationNameMap
2724  std::pair<AnsiString, char>TempMapPair;
2725 
2726  ContinuationNameMap.clear();
2727  for(int x = 0; x < Track->TrackVectorSize(); x++)
2728  {
2729  if((Track->TrackElementAt(1058, x).TrackType == Continuation) && (Track->TrackElementAt(1059, x).ActiveTrackElementName != ""))
2730  {
2731  TempMapPair.first = Track->TrackElementAt(1060, x).ActiveTrackElementName;
2732  TempMapPair.second = 'x'; // unused
2733  ContinuationNameMap.insert(TempMapPair);
2734  }
2735  }
2736 
2737 //check (provided TrackFinished is true) if any named (red) locations are without platforms, ie concourses only or concourses and foot crossings
2738 //(don't report blue areas without track as these unlikely to be mistakes)
2739 
2740  if(TrackFinished)
2741  {
2742  AnsiString Name = "";
2743  typedef std::list<AnsiString> TNoPlatsList;
2744  TNoPlatsList::iterator NPLIt;
2745  TNoPlatsList NoPlatsList;
2746  typedef std::list<AnsiString> TLocNameList;
2747  TLocNameList LocNameList; //single entry for each name
2750  for(TLocationNameMultiMapIterator LNMMIt = LocationNameMultiMap.begin(); LNMMIt != LocationNameMultiMap.end(); LNMMIt++)
2751  {
2752  LocNameList.push_back(LNMMIt->first);
2753  }
2754  LocNameList.sort();
2755  LocNameList.unique();
2756  for(TLocNameList::iterator LNLIt = LocNameList.begin(); LNLIt != LocNameList.end(); LNLIt++)
2757  {
2758  Name = *LNLIt;
2759  MMRange = LocationNameMultiMap.equal_range(Name);
2760  if(MMRange.first == MMRange.second) //can't find it - should always do but include as a safeguard
2761  {
2762  continue;
2763  }
2764  for(TLocationNameMultiMapIterator LNMMIt = MMRange.first; LNMMIt != MMRange.second; LNMMIt++)
2765  {
2766  if((LNMMIt->second) < 0) //active track element
2767  {
2768  if(TrackElementAt(1401, -1 - LNMMIt->second).TrackType != FootCrossing)
2769  {
2770  break;
2771  }
2772  }
2773  else //inactive
2774  {
2775  if(InactiveTrackElementAt(1402, LNMMIt->second).TrackType != Concourse)
2776  {
2777  break;
2778  }
2779  }
2780  TempIt = MMRange.second;
2781  if(LNMMIt == --TempIt) //reached last named element & all concourses or foot crossings
2782  {
2783  NoPlatsList.push_back(Name);
2784  }
2785  }
2786  }
2787  if(!NoPlatsList.empty())
2788  {
2789  AnsiString NoPlatsAnsiList = "";
2790  for(NPLIt = NoPlatsList.begin(); NPLIt != NoPlatsList.end(); NPLIt++)
2791  {
2792  NoPlatsAnsiList += *NPLIt + '\n';
2793  }
2794  if(!NoPlatsMessageSent)
2795  {
2796  if(NoPlatsList.size() > 1)
2797  {
2798  ShowMessage("Please note: the following locations have no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2799  }
2800  else
2801  {
2802  ShowMessage("Please note: the following location has no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2803  }
2804  NoPlatsMessageSent = true;
2805  }
2806  }
2807  }
2808  Utilities->CallLogPop(440);
2809  return(true);
2810 }
2811 
2812 // ---------------------------------------------------------------------------
2813 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2814 // unused - too time-consuming - double brute force search
2815 {
2816  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2817  int NewHLoc, NewVLoc;
2818  bool ConnectionFoundFlag, LinkFoundFlag;
2819 
2820  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2821  {
2822  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2823  {
2824  if(TrackElementAt(1061, x).Link[y] <= 0)
2825  {
2826  continue; // no link
2827  }
2828  if(TrackElementAt(1062, x).Config[y] == End)
2829  {
2830  continue; // buffer or continuation
2831  }
2832  if(TrackElementAt(1063, x).Config[y] == Gap)
2833  {
2834  continue; // gap jump
2835  }
2836  // get required H & V for track element joining link 'y'
2837  NewHLoc = TrackElementAt(1064, x).HLoc + LinkHVArray[TrackElementAt(1065, x).Link[y]][0];
2838  NewVLoc = TrackElementAt(1066, x).VLoc + LinkHVArray[TrackElementAt(1067, x).Link[y]][1];
2839  // find track element if present
2840  ConnectionFoundFlag = false;
2841  for(unsigned int z = 0; z < TrackVector.size(); z++)
2842  {
2843 // if(TrackElementAt(5, z).TrackType == Platform)
2844 // continue; //skip platforms
2845  if((TrackElementAt(1068, z).HLoc == NewHLoc) && (TrackElementAt(1069, z).VLoc == NewVLoc))
2846  {
2847  ConnectionFoundFlag = true;
2848  // find connecting link in the newly found track element if there is one
2849  LinkFoundFlag = false;
2850  for(unsigned int a = 0; a < 4; a++)
2851  {
2852  if(TrackElementAt(1070, z).Link[a] == (10 - TrackElementAt(1071, x).Link[y]))
2853  {
2854  LinkFoundFlag = true;
2855  }
2856  }
2857  // if there isn't a corresponding link set the invert values for the offending element
2858  if(!LinkFoundFlag)
2859  {
2860  HLoc = TrackElementAt(1072, x).HLoc;
2861  VLoc = TrackElementAt(1073, x).VLoc;
2862  Utilities->CallLogPop(441);
2863  return(true);
2864  }
2865  break; // success, so break out of 'z' loop
2866  } // if((TrackElementAt(, z).HLoc== NewHLoc) &&....
2867 
2868  } // for z...
2869  // if there isn't a connection set the invert values for the offending element
2870  if(!ConnectionFoundFlag)
2871  {
2872  HLoc = TrackElementAt(1074, x).HLoc;
2873  VLoc = TrackElementAt(1075, x).VLoc;
2874  Utilities->CallLogPop(442);
2875  return(true);
2876  }
2877  } // for y....
2878  } // for x...
2879  Utilities->CallLogPop(443);
2880  return(false); // all OK
2881 }
2882 
2883 // ---------------------------------------------------------------------------
2884 
2885 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2886 {
2887  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2888  TrackElement.LogTrack(0));
2889  bool FoundFlag;
2890 
2891  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2892  if(FoundFlag)
2893  {
2894  TrackElement = TrackElementAt(1076, Position);
2895  }
2896  Utilities->CallLogPop(444);
2897  return(FoundFlag);
2898 }
2899 
2900 // ---------------------------------------------------------------------------
2901 
2903 {
2904  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2905  if(NextTrackElementPtr >= TrackVector.end())
2906  {
2907  Utilities->CallLogPop(1336);
2908  return(false);
2909  }
2910  Next = *NextTrackElementPtr;
2912  Utilities->CallLogPop(1337);
2913  return(true);
2914 }
2915 
2916 // ---------------------------------------------------------------------------
2917 
2919 {
2920  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2922  {
2923  Utilities->CallLogPop(1338);
2924  return(false);
2925  }
2926  Next = *NextTrackElementPtr;
2928  Utilities->CallLogPop(1339);
2929  return(true);
2930 }
2931 
2932 // ---------------------------------------------------------------------------
2933 
2934 int TTrack::NumberOfGaps(int Caller)
2935 
2936 {
2937  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2938  int Count = 0;
2939 
2940  if(TrackVector.size() == 0)
2941  {
2942  Utilities->CallLogPop(1340);
2943  return(0);
2944  }
2945  for(unsigned int x = 0; x < TrackVector.size(); x++)
2946  {
2947  if(TrackElementAt(1077, x).TrackType == GapJump)
2948  {
2949  Count++;
2950  }
2951  }
2952  Utilities->CallLogPop(1341);
2953  return(Count);
2954 }
2955 
2956 // ---------------------------------------------------------------------------
2958 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2959 // returns true for any unset gaps
2960 {
2961  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2962  bool UnsetGaps = false;
2963 
2964  if(TrackVector.size() == 0)
2965  {
2966  Utilities->CallLogPop(445);
2967  return(false);
2968  }
2969  for(unsigned int x = 0; x < TrackVector.size(); x++)
2970  {
2971  if(TrackElementAt(1078, x).TrackType != GapJump)
2972  {
2973  for(unsigned int y = 0; y < 4; y++)
2974  {
2975  TrackElementAt(1079, x).Conn[y] = -1;
2976  TrackElementAt(1080, x).ConnLinkPos[y] = -1;
2977  }
2978  }
2979  else // GapJump
2980  {
2981 // int tempint = TrackElementAt(, x).Conn[0);
2982 
2983  if(TrackElementAt(1081, x).Conn[0] == -1) // unset if -1
2984  {
2985  for(unsigned int y = 0; y < 4; y++)
2986  {
2987  TrackElementAt(1082, x).Conn[y] = -1;
2988  TrackElementAt(1083, x).ConnLinkPos[y] = -1;
2989  }
2990  UnsetGaps = true;
2991  continue; // to next 'x'
2992  }
2993  else // set, but may not have matching element, or that element may not be set
2994  {
2995  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2996  {
2997  TrackElementAt(1084, x).Conn[y] = -1;
2998  TrackElementAt(1085, x).ConnLinkPos[y] = -1;
2999  }
3000 
3001  if(TrackElementAt(1086, TrackElementAt(1104, x).Conn[0]).TrackType != GapJump)
3002  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
3003  {
3004  for(unsigned int y = 0; y < 4; y++)
3005  {
3006  TrackElementAt(1087, x).Conn[y] = -1;
3007  TrackElementAt(1088, x).ConnLinkPos[y] = -1;
3008  }
3009  UnsetGaps = true;
3010  continue; // to next 'x'
3011  }
3012 // here if gap connection is itself a GapJump
3013  if(TrackElementAt(1089, TrackElementAt(1105, x).Conn[0]).Conn[0] != (int)x)
3014  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
3015  // if not clear Conns & CLks & reset Lk[0]
3016  {
3017  for(unsigned int y = 0; y < 4; y++)
3018  {
3019  TrackElementAt(1090, x).Conn[y] = -1;
3020  TrackElementAt(1091, x).ConnLinkPos[y] = -1;
3021  }
3022  UnsetGaps = true;
3023  continue; // to next 'x'
3024  }
3025 // here if gap connection itself points back to 'x' so these two GapJumps match properly
3026 // hence no more action needed on these Conns & CLks
3027  }
3028  } // else //gap jump
3029 
3030  } // for x...
3031  Utilities->CallLogPop(446);
3032  return(UnsetGaps);
3033 }
3034 
3035 // ---------------------------------------------------------------------------
3036 
3037 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
3038 {
3039 // VecFile already open and its pointer at right place on calling
3040  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
3041  int TempInt;
3042 
3043  TrackClear(1);
3044 // load track elements
3045  int NumberOfActiveElements = 0;
3046 
3047  GraphicsFollow = false;
3048  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3049  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
3050 
3051  if(MarkerString[MarkerString.Length()] == '1')
3052  {
3053  GraphicsFollow = true;
3054  }
3055  for(int x = 0; x < NumberOfActiveElements; x++)
3056  {
3057  VecFile >> TempInt; // TrackVectorNumber, not used
3058  VecFile >> TempInt; // SpeedTag
3059  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3060  VecFile >> TempInt;
3061  TrackElement.HLoc = TempInt;
3062  VecFile >> TempInt;
3063  TrackElement.VLoc = TempInt;
3064  if(TrackElement.TrackType == GapJump)
3065  {
3066  VecFile >> TempInt;
3067  TrackElement.ConnLinkPos[0] = TempInt;
3068  VecFile >> TempInt;
3069  TrackElement.Conn[0] = TempInt;
3070  }
3071  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3072  {
3073  VecFile >> TempInt;
3074  TrackElement.Attribute = TempInt;
3075  }
3076  if(TrackElement.TrackType == SignalPost)
3077  {
3078  VecFile >> TempInt;
3079  if(TempInt == 0)
3080  {
3081  TrackElement.CallingOnSet = false;
3082  }
3083  else
3084  {
3085  TrackElement.CallingOnSet = true;
3086  }
3087  }
3088  VecFile >> TempInt;
3089  TrackElement.Length01 = TempInt;
3090  VecFile >> TempInt;
3091  TrackElement.Length23 = TempInt;
3092  VecFile >> TempInt;
3093  if((TempInt != -1) && (TempInt < 10))
3094  {
3095  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3096  }
3097  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3098  {
3099  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3100  }
3101  TrackElement.SpeedLimit01 = TempInt;
3102  VecFile >> TempInt;
3103  if((TempInt != -1) && (TempInt < 10))
3104  {
3105  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3106  }
3107  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3108  {
3109  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3110  }
3111  TrackElement.SpeedLimit23 = TempInt;
3112 
3113  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3114  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
3115  SetElementID(0, TrackElement);
3116  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
3117 // new for v0.6
3118  if(TrackElement.TrackType == SignalPost)
3119  {
3120  if(Marker[1] == '3')
3121  {
3122  TrackElement.SigAspect = TTrackElement::ThreeAspect;
3123  }
3124  else if(Marker[1] == '2')
3125  {
3126  TrackElement.SigAspect = TTrackElement::TwoAspect;
3127  }
3128  else if(Marker[1] == 'G')
3129  {
3130  TrackElement.SigAspect = TTrackElement::GroundSignal;
3131  }
3132  else
3133  {
3134  TrackElement.SigAspect = TTrackElement::FourAspect;
3135  }
3136  }
3137  if(TrackElement.SpeedTag != 0)
3138  {
3139  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
3140  }
3141  }
3142  int NumberOfInactiveElements = 0;
3143 
3144  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3145  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
3146  for(int x = 0; x < NumberOfInactiveElements; x++)
3147  {
3148  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
3149  VecFile >> TempInt; // SpeedTag
3150  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3151  VecFile >> TempInt;
3152  TrackElement.HLoc = TempInt;
3153  VecFile >> TempInt;
3154  TrackElement.VLoc = TempInt;
3155  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3156  SetElementID(3, TrackElement);
3157  TrackPush(9, TrackElement);
3158  Utilities->LoadFileString(VecFile); // marker
3159  }
3160  bool LocError = false; // needed for TryToConnectTrack but not used
3161  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3162 
3163  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3164  {
3165  SetTrackFinished(true);
3166  }
3167  else
3168  {
3169  SetTrackFinished(false);
3170  }
3171 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3172 // CheckMapAndInactiveTrack(8);
3173 // CheckLocationNameMultiMap(10);
3174  Utilities->CallLogPop(448);
3175 }
3176 
3177 // ---------------------------------------------------------------------------
3178 
3179 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3180 {
3181 // VecFile already open and its pointer at right place on calling
3182  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3183 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3184 // & load into UserGraphicItem then store in UserGraphicVector
3185  UserGraphicVector.clear();
3186  TUserGraphicItem UGI;
3187  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3188 
3189  for(int x = 0; x < NumberOfGraphics; x++)
3190  {
3191  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3192  UGI.HPos = Utilities->LoadFileInt(VecFile);
3193  UGI.VPos = Utilities->LoadFileInt(VecFile);
3194  UGI.Width = 0; // provisional value
3195  UGI.Height = 0; // provisional value
3196  UGI.UserGraphic = NULL; // provisional value
3197  UserGraphicVector.push_back(UGI);
3198  }
3199 // now load the map & set Width, Height & TPicture*
3200  bool FileError = false;
3201 
3202  for(int x = 0; x < NumberOfGraphics; x++)
3203  {
3204  if(FileError)
3205  {
3206  break; // otherwise keeps going round the loop
3207  }
3208  UGI = UserGraphicVectorAt(0, x);
3209  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3210  {
3211  try
3212  {
3213 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3214  UGME.first = UGI.FileName;
3215  UGME.second = new TPicture;
3216  UGME.second->LoadFromFile(UGME.first); // errors caught below
3217  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3218  {
3219  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3220  }
3221  UGI.UserGraphic = UGME.second;
3222  UGI.Width = UGI.UserGraphic->Width;
3223  UGI.Height = UGI.UserGraphic->Height;
3224  UserGraphicVectorAt(1, x) = UGI;
3225  }
3226  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3227  {
3228  //message already sent in CheckUserGraphics
3229  FileError = true;
3230  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3231  if(!UserGraphicMap.empty())
3232  {
3233  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3234  {
3235  delete UGMIt->second;
3236  }
3237  UserGraphicMap.clear();
3238  }
3239  }
3240  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3241  {
3242  //message already sent in CheckUserGraphics
3243  FileError = true;
3244  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3245  if(!UserGraphicMap.empty())
3246  {
3247  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3248  {
3249  delete UGMIt->second;
3250  }
3251  UserGraphicMap.clear();
3252  }
3253  }
3254  }
3255  else
3256  {
3257  bool FoundInMap = false;
3258  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3259  {
3260  if(UGI.FileName == UGMIt->first) // already exists in map
3261  {
3262  UGI.UserGraphic = UGMIt->second;
3263  UGI.Width = UGI.UserGraphic->Width;
3264  UGI.Height = UGI.UserGraphic->Height;
3265  UserGraphicVectorAt(2, x) = UGI;
3266  FoundInMap = true;
3267  break;
3268  }
3269  }
3270  if(!FoundInMap)
3271  {
3272  try
3273  {
3275  UGME.first = UGI.FileName;
3276  UGME.second = new TPicture;
3277  UGME.second->LoadFromFile(UGME.first); // errors caught below
3278  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3279  {
3280  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3281  }
3282  UGI.UserGraphic = UGME.second;
3283  UGI.Width = UGI.UserGraphic->Width;
3284  UGI.Height = UGI.UserGraphic->Height;
3285  UserGraphicVectorAt(3, x) = UGI;
3286  }
3287  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3288  {
3289  //message already sent in CheckUserGraphics
3290  FileError = true;
3291  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3292  if(!UserGraphicMap.empty())
3293  {
3294  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3295  {
3296  delete UGMIt->second;
3297  }
3298  UserGraphicMap.clear();
3299  }
3300  }
3301  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3302  {
3303  //message already sent in CheckUserGraphics
3304  FileError = true;
3305  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3306  if(!UserGraphicMap.empty())
3307  {
3308  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3309  {
3310  delete UGMIt->second;
3311  }
3312  UserGraphicMap.clear();
3313  }
3314  }
3315  }
3316  }
3317  }
3318  Utilities->CallLogPop(2167);
3319 }
3320 
3321 // ---------------------------------------------------------------------------
3322 
3323 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3324 {
3325 // VecFile already open and its pointer at right place on calling
3326 // if GraphicsFollow true, then save Marker as **Active elements**1
3327 // save trackfinished flag
3328  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3329  TTrackElement TrackElement, InactiveTrackElement;
3330 
3331 // save track elements
3332  Utilities->SaveFileInt(VecFile, TrackVector.size());
3333  if(GraphicsFollow)
3334  {
3335  VecFile << "**Active elements**1" << '\0' << '\n';
3336  }
3337  else
3338  {
3339  VecFile << "**Active elements**" << '\0' << '\n';
3340  }
3341  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3342  {
3343  TrackElement = TrackElementAt(1092, x);
3344  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3345  VecFile << TrackElement.SpeedTag << '\n';
3346  VecFile << TrackElement.HLoc << '\n';
3347  VecFile << TrackElement.VLoc << '\n';
3348  if(TrackElement.TrackType == GapJump)
3349  {
3350  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3351  VecFile << TrackElement.Conn[0] << '\n';
3352  }
3353  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3354  {
3355  VecFile << TrackElement.Attribute << '\n';
3356  }
3357  if(TrackElement.TrackType == SignalPost)
3358  {
3359  if(TrackElement.CallingOnSet)
3360  {
3361  VecFile << int(1) << '\n';
3362  }
3363  else
3364  {
3365  VecFile << int(0) << '\n';
3366  }
3367  }
3368  VecFile << TrackElement.Length01 << '\n';
3369  VecFile << TrackElement.Length23 << '\n';
3370  VecFile << TrackElement.SpeedLimit01 << '\n';
3371  VecFile << TrackElement.SpeedLimit23 << '\n';
3372  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3373  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3374 // new for v0.6
3375  if(TrackElement.TrackType == SignalPost)
3376  {
3377  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3378  {
3379  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3380  }
3381  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3382  {
3383  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3384  }
3385  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3386  {
3387  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3388  }
3389  else // 4 aspect
3390  {
3391  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3392  }
3393  }
3394  else
3395  {
3396  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3397  }
3398  }
3399 
3400  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3401  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3402  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3403  {
3404  InactiveTrackElement = InactiveTrackElementAt(136, x);
3405  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3406  VecFile << InactiveTrackElement.SpeedTag << '\n';
3407  VecFile << InactiveTrackElement.HLoc << '\n';
3408  VecFile << InactiveTrackElement.VLoc << '\n';
3409  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3410  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3411  }
3412  Utilities->CallLogPop(449);
3413 }
3414 
3415 // ---------------------------------------------------------------------------
3416 
3417 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3418 {
3419 // VecFile already open and its pointer at right place on calling
3420 // check trackfinished flag
3421 // inactive elements follow immediately after active elements, no need to check for a marker between them
3422  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3423  int TempInt;
3424 
3425  GraphicsFollow = false;
3426  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3427  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3428  {
3429  Utilities->CallLogPop(1513);
3430  return(false);
3431  }
3432 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3433  AnsiString MarkerString;
3434 
3435  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3436  {
3437  Utilities->CallLogPop(1758);
3438  return(false);
3439  }
3440  if(MarkerString[MarkerString.Length()] == '1')
3441  {
3442  GraphicsFollow = true;
3443  }
3444  for(int x = 0; x < NumberOfActiveElements; x++)
3445  {
3446  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3447  {
3448  Utilities->CallLogPop(1759);
3449  return(false);
3450  }
3451  VecFile >> TempInt;
3452  int SpeedTag = TempInt;
3453  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3454  {
3455  Utilities->CallLogPop(1514);
3456  return(false);
3457  }
3458  VecFile >> TempInt;
3459  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3460  {
3461  Utilities->CallLogPop(1495);
3462  return(false);
3463  }
3464  VecFile >> TempInt;
3465  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3466  {
3467  Utilities->CallLogPop(1497);
3468  return(false);
3469  }
3470  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3471  {
3472  VecFile >> TempInt;
3473  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3474  {
3475  Utilities->CallLogPop(1499);
3476  return(false);
3477  }
3478  VecFile >> TempInt;
3479  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3480  {
3481  Utilities->CallLogPop(1500);
3482  return(false);
3483  }
3484  }
3485  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3486  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3487  {
3488  VecFile >> TempInt;
3489  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3490  {
3491  Utilities->CallLogPop(1502);
3492  return(false);
3493  }
3494  }
3495  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3496  {
3497  VecFile >> TempInt;
3498  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3499  {
3500  Utilities->CallLogPop(1155);
3501  return(false);
3502  }
3503  }
3504  VecFile >> TempInt;
3505  if((TempInt < -1) || (TempInt > 999999)) // Length01
3506  {
3507  Utilities->CallLogPop(1503);
3508  return(false);
3509  }
3510  VecFile >> TempInt;
3511  if((TempInt < -1) || (TempInt > 999999)) // Length23
3512  {
3513  Utilities->CallLogPop(1504);
3514  return(false);
3515  }
3516  VecFile >> TempInt;
3517  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3518  {
3519  Utilities->CallLogPop(1505);
3520  return(false);
3521  }
3522  VecFile >> TempInt;
3523  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3524  {
3525  Utilities->CallLogPop(1506);
3526  return(false);
3527  }
3528  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3529  {
3530  Utilities->CallLogPop(1142);
3531  return(false); // LocationName
3532  }
3533  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3534  {
3535  Utilities->CallLogPop(1143);
3536  return(false); // ActiveTrackElementName
3537  }
3538  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3539  {
3540  Utilities->CallLogPop(1787);
3541  return(false); // marker
3542  }
3543  }
3544  int NumberOfInactiveElements = 0;
3545 
3546  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3547  if(NumberOfInactiveElements < 0) // No of active elements
3548  {
3549  Utilities->CallLogPop(1493);
3550  return(false);
3551  }
3552  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3553  {
3554  Utilities->CallLogPop(1764);
3555  return(false); // **Inactive elements** marker
3556  }
3557  for(int x = 0; x < NumberOfInactiveElements; x++)
3558  {
3559  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3560  {
3561  Utilities->CallLogPop(1765);
3562  return(false);
3563  }
3564  VecFile >> TempInt;
3565  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3566  {
3567  Utilities->CallLogPop(1494);
3568  return(false);
3569  }
3570  VecFile >> TempInt;
3571  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3572  {
3573  Utilities->CallLogPop(1496);
3574  return(false);
3575  }
3576  VecFile >> TempInt;
3577  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3578  {
3579  Utilities->CallLogPop(1498);
3580  return(false);
3581  }
3582  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3583  {
3584  Utilities->CallLogPop(1144);
3585  return(false); // LocationName
3586  }
3587  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3588  {
3589  Utilities->CallLogPop(1788);
3590  return(false); // marker
3591  }
3592  }
3593  Utilities->CallLogPop(1507);
3594  return(true);
3595 }
3596 
3597 // ---------------------------------------------------------------------------
3598 
3599 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3600 {
3601  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3602  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3603 
3604  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3605  {
3606  Utilities->CallLogPop(2168);
3607  return(false);
3608  }
3609  // filename in Graphics folder, then HPos, then VPos
3610  AnsiString FileName = "", TempStr = "";
3611 
3612  for(int x = 0; x < NumberOfGraphics; x++)
3613  {
3614  TPicture *TempPicture = new TPicture;
3615  try
3616  {
3617  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3618  {
3619  Utilities->CallLogPop(2169);
3620  delete TempPicture;
3621  return(false);
3622  }
3623  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3624  delete TempPicture;
3625  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3626  {
3627  Utilities->CallLogPop(2170);
3628  return(false);
3629  }
3630  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3631  {
3632  Utilities->CallLogPop(2171);
3633  return(false);
3634  }
3635  }
3636  catch(const EInvalidGraphic &e) //non error catch
3637  {
3638  //move file pointer to end of graphic section for later checks in session files
3639  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3640  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3641  for(int y = x + 1; y < NumberOfGraphics; y++)
3642  {
3643  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3644  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3645  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3646  }
3647  ShowMessage(FileName +
3648  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3649  Utilities->CallLogPop(2172);
3650  delete TempPicture;
3651  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3652  }
3653  catch(const Exception &e) //non error catch
3654  {
3655  //move file pointer to end of graphic section for later checks in session files
3656  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3657  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3658  for(int y = x + 1; y < NumberOfGraphics; y++)
3659  {
3660  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3661  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3662  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3663  }
3664  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3665  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3666  Utilities->CallLogPop(2173);
3667  delete TempPicture;
3668  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3669  }
3670  }
3671  Utilities->CallLogPop(2174);
3672  return(true);
3673 }
3674 
3675 // ---------------------------------------------------------------------------
3676 
3677 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3678 {
3679  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3680  int VecSize = Track->BarriersDownVector.size();
3681 
3682  Utilities->SaveFileInt(OutFile, VecSize);
3683  for(int x = 0; x < VecSize; x++)
3684  {
3686  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3687  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3688  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3689  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3690  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3691  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3692  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3693  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3694  }
3695  Utilities->CallLogPop(1963);
3696 }
3697 
3698 // ---------------------------------------------------------------------------
3699 
3700 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3701 {
3702  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3703  int VecSize = Track->ChangingLCVector.size();
3704 
3705  Utilities->SaveFileInt(OutFile, VecSize);
3706  for(int x = 0; x < VecSize; x++)
3707  {
3709  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3710  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3711  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3712  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3713  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3714  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3715  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3716  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3717  }
3718  Utilities->CallLogPop(1980);
3719 }
3720 
3721 // ---------------------------------------------------------------------------
3722 
3723 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3724 {
3725  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3726  int VecSize = Utilities->LoadFileInt(VecFile);
3727 
3728  for(int x = 0; x < VecSize; x++)
3729  {
3730  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3731  {
3732  Utilities->CallLogPop(1970);
3733  return(false);
3734  }
3735  if(!Utilities->CheckFileBool(VecFile))
3736  {
3737  Utilities->CallLogPop(1971);
3738  return(false);
3739  }
3740  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3741  {
3742  Utilities->CallLogPop(1972);
3743  return(false);
3744  }
3745  if(!Utilities->CheckFileDouble(VecFile))
3746  {
3747  Utilities->CallLogPop(1973);
3748  return(false);
3749  }
3750  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3751  {
3752  Utilities->CallLogPop(1974);
3753  return(false);
3754  }
3755  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3756  {
3757  Utilities->CallLogPop(1975);
3758  return(false);
3759  }
3760  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3761  {
3762  Utilities->CallLogPop(1976);
3763  return(false);
3764  }
3765  if(!Utilities->CheckFileDouble(VecFile))
3766  {
3767  Utilities->CallLogPop(1977);
3768  return(false);
3769  }
3770  }
3771  Utilities->CallLogPop(1978);
3772  return(true);
3773 }
3774 
3775 // ---------------------------------------------------------------------------
3776 
3777 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3778 {
3779  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3780  int VecSize = Utilities->LoadFileInt(VecFile);
3781 
3782  for(int x = 0; x < VecSize; x++)
3783  {
3784  TActiveLevelCrossing TALC;
3785  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3786  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3787  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3788  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3789  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3790  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3791  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3792  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3793  BarriersDownVector.push_back(TALC);
3794  }
3795  Utilities->CallLogPop(1979);
3796 }
3797 
3798 // ---------------------------------------------------------------------------
3799 
3800 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3801 /*
3802  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3803  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3804  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3805 */
3806 {
3807  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3808  TTrackElement Next;
3809 
3810 // Disp->ClearDisplay();
3812  while(ReturnNextInactiveTrackElement(0, Next))
3813  {
3814  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3815  {
3816  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3817  {
3818  // only plot if on screen, to save time
3819  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3821  {
3822  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3823  }
3824  }
3825  }
3826  }
3827 
3828  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3829 
3830  NextTrackElementPtr = TrackVector.begin();
3831  while(ReturnNextTrackElement(0, Next))
3832  {
3833  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3834  {
3835  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3837  {
3838  if(Next.TrackType == Points)
3839  {
3840  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3841  }
3842  else if(Next.TrackType == SignalPost)
3843  {
3844  PlotSignal(9, Next, Disp);
3845  }
3846  else if(Next.TrackType == GapJump)
3847  {
3848  PlotGap(0, Next, Disp);
3849  }
3850  else if(Next.TrackType == Continuation) //added for multiplayer graphic overlays
3851  {
3852  PlotContinuation(0, Next, Disp);
3853  }
3854  else
3855  {
3856  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3857  }
3858  }
3859  }
3860  }
3861 
3862  if(BothPointFilletsAndBasicLCs)
3863  {
3865  while(ReturnNextInactiveTrackElement(4, Next))
3866  {
3867  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3868  {
3869  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3870  {
3871  // only plot if on screen, to save time, & OK as plotting one by one here
3872  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3874  {
3875  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3876  {
3877  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3878  }
3879  else
3880  {
3881  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3882  }
3883  }
3884  }
3885  }
3886  }
3887  }
3888  Disp->Update();
3889  Utilities->CallLogPop(468);
3890 }
3891 
3892 // ---------------------------------------------------------------------------
3893 
3894 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3895 {
3896  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3897  if(UserGraphicVector.empty())
3898  {
3899  Utilities->CallLogPop(2175);
3900  return;
3901  }
3902  TUserGraphicItem UGI;
3903 
3904  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3905  {
3906  UGI = UserGraphicVectorAt(4, x);
3907  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3908  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3909  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3910  {
3911  Disp->PlotAndAddUserGraphic(0, UGI);
3912  }
3913  }
3914  Disp->Update();
3915  Utilities->CallLogPop(2176);
3916 }
3917 
3918 // ---------------------------------------------------------------------------
3919 
3920 void TTrack::WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap) //added text after inactives at v2.10.0
3921 /*
3922  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3923 */
3924 {
3925  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackAndTextToImage");
3926 // need to change graphics back to black on white if have a dark background
3927  TColor OldTransparentColour = Utilities->clTransparent;
3928 
3930  {
3931  Utilities->clTransparent = TColor(0xFFFFFF); // white
3934  }
3935  TTrackElement Next;
3936 
3937  Bitmap->Canvas->CopyMode = cmSrcCopy;
3939  Graphics::TBitmap *GraphicOutput;
3940 
3941  while(ReturnNextInactiveTrackElement(2, Next))
3942  {
3943  GraphicOutput = Next.GraphicPtr;
3944  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3945  {
3946  if(Next.LocationName == "") // plot as named or unnamed (striped)
3947  {
3948  // default is not striped
3949  switch(Next.SpeedTag)
3950  {
3951  case 76: // t platform
3952  GraphicOutput = RailGraphics->gl76Striped;
3953  break;
3954 
3955  case 77: // h platform
3956  GraphicOutput = RailGraphics->bm77Striped;
3957  break;
3958 
3959  case 78: // v platform
3960  GraphicOutput = RailGraphics->bm78Striped;
3961  break;
3962 
3963  case 79: // r platform
3964  GraphicOutput = RailGraphics->gl79Striped;
3965  break;
3966 
3967  case 96: // concourse
3968  GraphicOutput = RailGraphics->ConcourseStriped;
3969  break;
3970 
3971  case 129: // v footbridge
3972  GraphicOutput = RailGraphics->gl129Striped;
3973  break;
3974 
3975  case 130: // h footbridge
3976  GraphicOutput = RailGraphics->gl130Striped;
3977  break;
3978 
3979  case 131: // non-station named loc
3980  GraphicOutput = RailGraphics->bmNameStriped;
3981  break;
3982 
3983  case 145: // v underpass
3984  GraphicOutput = RailGraphics->gl145Striped;
3985  break;
3986 
3987  case 146: // h underpass
3988  GraphicOutput = RailGraphics->gl146Striped;
3989  break;
3990 
3991  default:
3992  GraphicOutput = Next.GraphicPtr;
3993  break;
3994  }
3995  }
3996  if(Next.SpeedTag == 144) // level crossing
3997  {
3998  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3999  {
4000  GraphicOutput = RailGraphics->LCBothVer;
4001  }
4002  else
4003  {
4004  GraphicOutput = RailGraphics->LCBothHor;
4005  }
4006  }
4007  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4008  }
4009  }
4010 
4011  TextHandler->WriteTextToImage(0, Bitmap); //so overwrites inactive elements //added at v2.10.0
4012 
4013 
4014  NextTrackElementPtr = TrackVector.begin();
4015  while(ReturnNextTrackElement(2, Next))
4016  {
4017  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4018  {
4019  if(Next.TrackType == Points) // plot both fillets
4020  {
4021  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4022  if(Next.SpeedTag < 28)
4023  {
4024  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4026  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4028  }
4029  else if(Next.SpeedTag < 132)
4030  {
4031  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4032  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
4033  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4034  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
4035  }
4036  else
4037  {
4038  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4039  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
4040  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4041  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
4042  }
4043  }
4044  else if(Next.TrackType == GapJump) // plot as connected or unconnected
4045  {
4046  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
4047  {
4048  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4049  }
4050  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
4051  {
4052  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
4053  }
4054  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
4055  {
4056  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4057  }
4058  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
4059  {
4060  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
4061  }
4062  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
4063  {
4064  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4065  }
4066  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
4067  {
4068  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
4069  }
4070  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
4071  {
4072  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4073  }
4074  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
4075  {
4076  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
4077  }
4078  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
4079  {
4080  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4081  }
4082  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
4083  {
4084  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
4085  }
4086  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
4087  {
4088  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4089  }
4090  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
4091  {
4092  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
4093  }
4094  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
4095  {
4096  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4097  }
4098  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
4099  {
4100  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
4101  }
4102  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
4103  {
4104  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4105  }
4106  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
4107  {
4108  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
4109  }
4110  }
4111  // below added for version 0.6, only stop signals to be drawn
4112  else if(Next.TrackType == SignalPost)
4113  {
4114  for(int x = 0; x < 40; x++)
4115  {
4116  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
4117  {
4118  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4119  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4120  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4121  int HOffset = 0;
4122  if(Next.SpeedTag > 73)
4123  {
4124  HOffset = 5;
4125  }
4126  else if(Next.SpeedTag == 71)
4127  {
4128  HOffset = 9;
4129  }
4130  int VOffset = 0;
4131  if(Next.SpeedTag == 69)
4132  {
4133  VOffset = 9;
4134  }
4135  else if(Next.SpeedTag == 72)
4136  {
4137  VOffset = 5;
4138  }
4139  else if(Next.SpeedTag == 74)
4140  {
4141  VOffset = 5;
4142  }
4143  Graphics::TBitmap *GraphicPtr;
4144  if(Next.SpeedTag > 71)
4145  {
4146  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4147  }
4148  else if(Next.SpeedTag < 70)
4149  {
4150  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4151  }
4152  else
4153  {
4154  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4155  }
4156  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4157  // plot special signal platform if present
4158  Graphics::TBitmap* SignalPlatformGraphic;
4159  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4160  {
4161  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4162  }
4163  // now plot signal (double yellow overwrites most of signal platform if present)
4164  // below amended for version 0.6
4166  {
4167  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4168  }
4169  else if(Next.SigAspect == TTrackElement::TwoAspect)
4170  {
4171  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4172  }
4173  else if(Next.SigAspect == TTrackElement::GroundSignal)
4174  {
4175  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4176  }
4177  else // 4 aspect
4178  {
4179  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4180  }
4181  break;
4182  }
4183  }
4184  }
4185  else
4186  {
4187  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4188  }
4189  }
4190  }
4191  if(OldTransparentColour != clB5G5R5)
4192  {
4193  Utilities->clTransparent = OldTransparentColour; // restore
4196  }
4197  Utilities->CallLogPop(1533);
4198 }
4199 
4200 // ---------------------------------------------------------------------------
4201 
4202 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4203 {
4204  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4205  if(UserGraphicVector.empty())
4206  {
4207  Utilities->CallLogPop(2192);
4208  return;
4209  }
4210  else
4211  {
4212  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4213  {
4214  Bitmap->Canvas->CopyMode = cmSrcCopy;
4215  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4216  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4217  }
4218  }
4219  Utilities->CallLogPop(2193);
4220 }
4221 
4222 // ---------------------------------------------------------------------------
4223 
4224 void TTrack::WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
4225 /*
4226  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4227  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4228 */
4229 {
4230  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackAndTextToImage");
4231 // need to change graphics back to black on white if have a dark background
4232  TColor OldTransparentColour = Utilities->clTransparent;
4233 
4235  {
4236  Utilities->clTransparent = TColor(0xFFFFFF); // white
4239  }
4240  TTrackElement Next;
4241 
4242  Bitmap->Canvas->CopyMode = cmSrcCopy;
4244  Graphics::TBitmap *GraphicOutput;
4245 
4246  while(ReturnNextInactiveTrackElement(3, Next))
4247  {
4248  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4249  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4250  {
4251  if(Next.SpeedTag == 144) // level crossing
4252  {
4253  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4254  if(BaseElement == 1) // hor element
4255  {
4256  if(Next.Attribute == 1) // open to trains
4257  {
4258  GraphicOutput = RailGraphics->LCBothHor;
4259  }
4260  else // plot as closed to trains if in any other state
4261  {
4262  GraphicOutput = RailGraphics->LCBothVer;
4263  }
4264  }
4265  else // vert element
4266  {
4267  if(Next.Attribute == 1) // open to trains
4268  {
4269  GraphicOutput = RailGraphics->LCBothVer;
4270  }
4271  else // plot as closed to trains if in any other state
4272  {
4273  GraphicOutput = RailGraphics->LCBothHor;
4274  }
4275  }
4276  }
4277  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4278  }
4279  }
4280 
4281  TextHandler->WriteTextToImage(1, Bitmap); //added at v2.10.0
4282 
4283  NextTrackElementPtr = TrackVector.begin();
4284  while(ReturnNextTrackElement(3, Next))
4285  {
4286  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4287  {
4288  if(Next.TrackType == Points) // plot active fillet
4289  {
4290  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4291  if(Next.SpeedTag < 28)
4292  {
4293  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4295  }
4296  else if(Next.SpeedTag < 132)
4297  {
4298  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4300  }
4301  else
4302  {
4303  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4305  }
4306  if(Next.Failed) //added at v2.13.0
4307  {
4308  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4310  }
4311 
4312  }
4313  else if(Next.TrackType == GapJump) // plot as connected
4314  {
4315  if(Next.SpeedTag == 88)
4316  {
4317  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4318  }
4319  else if(Next.SpeedTag == 89)
4320  {
4321  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4322  }
4323  else if(Next.SpeedTag == 90)
4324  {
4325  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4326  }
4327  else if(Next.SpeedTag == 91)
4328  {
4329  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4330  }
4331  else if(Next.SpeedTag == 92)
4332  {
4333  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4334  }
4335  else if(Next.SpeedTag == 93)
4336  {
4337  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4338  }
4339  else if(Next.SpeedTag == 94)
4340  {
4341  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4342  }
4343  else if(Next.SpeedTag == 95)
4344  {
4345  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4346  }
4347  }
4348  else if(Next.TrackType == SignalPost) //plot in correct colour
4349  {
4350  for(int x = 0; x < 40; x++)
4351  {
4352  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4353  {
4354  //plot blank first, then plot platform if present - (always not striped for operating railway)
4355  //note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4356  //in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4357  int HOffset = 0;
4358  if(Next.SpeedTag > 73)
4359  {
4360  HOffset = 5;
4361  }
4362  else if(Next.SpeedTag == 71)
4363  {
4364  HOffset = 9;
4365  }
4366  int VOffset = 0;
4367  if(Next.SpeedTag == 69)
4368  {
4369  VOffset = 9;
4370  }
4371  else if(Next.SpeedTag == 72)
4372  {
4373  VOffset = 5;
4374  }
4375  else if(Next.SpeedTag == 74)
4376  {
4377  VOffset = 5;
4378  }
4379  Graphics::TBitmap *GraphicPtr;
4380  if(Next.SpeedTag > 71)
4381  {
4382  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4383  }
4384  else if(Next.SpeedTag < 70)
4385  {
4386  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4387  }
4388  else
4389  {
4390  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4391  }
4392  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4393  // plot special signal platform if present
4394  Graphics::TBitmap* SignalPlatformGraphic;
4395  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4396  {
4397  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4398  }
4399  if(!Next.Failed)
4400  {
4401  // now plot signal (double yellow overwrites most of signal platform if present)
4402  // below amended for version 0.6
4404  {
4405  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4406  }
4407  else if(Next.SigAspect == TTrackElement::TwoAspect)
4408  {
4409  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4410  }
4411  else if(Next.SigAspect == TTrackElement::GroundSignal)
4412  {
4413  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4414  }
4415  else // 4 aspect
4416  {
4417  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4418  }
4419  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4420  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4421  {
4422  if(Next.SpeedTag == 68)
4423  {
4424  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4425  }
4426  if(Next.SpeedTag == 69)
4427  {
4428  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4429  }
4430  if(Next.SpeedTag == 70)
4431  {
4432  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4433  }
4434  if(Next.SpeedTag == 71)
4435  {
4436  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4437  }
4438  if(Next.SpeedTag == 72)
4439  {
4440  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4441  }
4442  if(Next.SpeedTag == 73)
4443  {
4444  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4445  }
4446  if(Next.SpeedTag == 74)
4447  {
4448  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4449  }
4450  if(Next.SpeedTag == 75)
4451  {
4452  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4453  }
4454  }
4455  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4456  {
4457  for(int x = 0; x < 40; x++)
4458  {
4459  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4460  {
4461  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4462  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4463  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4464  // plot special signal platform if present
4465  Graphics::TBitmap* SignalPlatformGraphic;
4466  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4467  {
4468  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4469  }
4470  // now plot signal
4471  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4472  break;
4473  }
4474  }
4475  }
4476  break;
4477  }
4478  else //added at v2.13.0
4479  {
4481  {
4482  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedSigTable[x % 5].SigPtr);
4483  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4484  }
4485  else
4486  {
4487  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedGroundSigTable[x % 5].SigPtr);
4488  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4489  }
4490  break;
4491  }
4492  }
4493  }
4494  }
4495  else
4496  {
4497  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4498  if(Next.Failed) //added at v2.13.0
4499  {
4500  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4502  }
4503  }
4504  }
4505  }
4506  if(OldTransparentColour != clB5G5R5)
4507  {
4508  Utilities->clTransparent = OldTransparentColour; // restore
4511  }
4512  Utilities->CallLogPop(1701);
4513 }
4514 
4515 // ---------------------------------------------------------------------------
4516 
4517 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4518 {
4519  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4520  for(unsigned int x = 0; x < TrackVector.size(); x++)
4521  {
4522  if(TrackElementAt(1093, x).TrackType == GapJump)
4523  {
4524  if(TrackElementAt(1094, x).Conn[0] > -1)
4525  {
4526  continue; // to next 'x' value as this element has already been set
4527  }
4528  // here if identify a GapJump element not yet set
4529  GapPos = x;
4530  GapHLoc = TrackElementAt(1095, x).HLoc;
4531  GapVLoc = TrackElementAt(1096, x).VLoc;
4532  // highlight it
4534  Utilities->CallLogPop(469);
4535  return(true);
4536  }
4537  }
4538  Utilities->CallLogPop(470);
4539  return(false);
4540 }
4541 
4542 // ---------------------------------------------------------------------------
4543 
4544 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4545 {
4546  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4547  AnsiString(VLoc));
4548  int Position;
4549  TTrackElement TrackElement;
4550 
4551  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4552  {
4553  Utilities->CallLogPop(471);
4554  return(false); // not found
4555  }
4556  if(TrackElement.TrackType != GapJump)
4557  {
4558  Utilities->CallLogPop(472);
4559  return(false); // found something but not a gap
4560  }
4561  if(Position == GapPos)
4562  {
4563  Utilities->CallLogPop(473);
4564  return(false); // selected original gap
4565  }
4566  if(TrackElementAt(1097, Position).Conn[0] != -1)
4567  {
4568  Utilities->CallLogPop(474);
4569  return(false); // already selected
4570  }
4571  TrackElementAt(1098, Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4572  TrackElementAt(1099, Position).ConnLinkPos[0] = 0;
4573  TrackElementAt(1100, GapPos).Conn[0] = Position; // set other one similarly
4574  TrackElementAt(1101, GapPos).ConnLinkPos[0] = 0;
4575 // now highlight the selected location
4576  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4577  Utilities->CallLogPop(475);
4578  return(true);
4579 }
4580 
4581 // ---------------------------------------------------------------------------
4582 
4583 bool TTrack::GapsUnset(int Caller)
4584 // returns true if there are gaps and any are unset
4585 {
4586  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4587  if(TrackVector.size() == 0)
4588  {
4589  Utilities->CallLogPop(476);
4590  return(false);
4591  }
4592  for(unsigned int x = 0; x < TrackVector.size(); x++)
4593  {
4594  if(TrackElementAt(1102, x).TrackType == GapJump)
4595  {
4596  if(TrackElementAt(1103, x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4597  {
4598  Utilities->CallLogPop(477);
4599  return(true);
4600  }
4601  else // set, but may not have matching element, or that element may not be set
4602  {
4603  if(TrackElementAt(1106, TrackElementAt(1107, x).Conn[0]).TrackType != GapJump)
4604  // check that the element pointed to by the gap link is a GapJump
4605  {
4606  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4607  Utilities->CallLogPop(1137);
4608  return(false);
4609  }
4610 // here if gap connection is itself a GapJump
4611  if(TrackElementAt(1108, TrackElementAt(1109, x).Conn[0]).Conn[0] != (int)x)
4612  // check that the element pointed to by the gap link is a GapJump & that its gap link
4613  // points back to 'x'
4614  {
4615  Utilities->CallLogPop(478);
4616  return(true);
4617  }
4618 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4619  }
4620  } // if(TrackElementAt(, x).TrackType == GapJump)
4621 
4622  } // for x...
4623  Utilities->CallLogPop(479);
4624  return(false);
4625 }
4626 
4627 // ---------------------------------------------------------------------------
4628 
4629 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4630 {
4631  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4632  for(unsigned int x = 0; x < TrackVector.size(); x++)
4633  {
4634  if(TrackElementAt(1110, x).TrackType == GapJump)
4635  {
4636  Utilities->CallLogPop(1105);
4637  return(false);
4638  }
4639  }
4640  Utilities->CallLogPop(1106);
4641  return(true);
4642 }
4643 
4644 // ---------------------------------------------------------------------------
4645 
4646 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4647 {
4648  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4649  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4650  {
4651  if(InactiveTrackElementAt(137, x).FixedNamedLocationElement)
4652  {
4653  Utilities->CallLogPop(1107);
4654  return(false);
4655  }
4656  }
4657  for(unsigned int x = 0; x < TrackVector.size(); x++)
4658  {
4659  if(TrackElementAt(1111, x).FixedNamedLocationElement)
4660  {
4661  Utilities->CallLogPop(1108);
4662  return(false);
4663  }
4664  }
4665  Utilities->CallLogPop(1109);
4666  return(true);
4667 }
4668 
4669 // ---------------------------------------------------------------------------
4670 
4672 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4673 // returns false otherwise or if there are no NamedLocationElements
4674 {
4675  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4676  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4677  {
4678  if(InactiveTrackElementAt(138, x).FixedNamedLocationElement)
4679  {
4680  if(InactiveTrackElementAt(139, x).LocationName == "")
4681  {
4682  Utilities->CallLogPop(1110);
4683  return(true);
4684  }
4685  }
4686  }
4687  for(unsigned int x = 0; x < TrackVector.size(); x++)
4688  {
4689  if(TrackElementAt(1112, x).FixedNamedLocationElement)
4690  {
4691  if(TrackElementAt(1113, x).LocationName == "")
4692  {
4693  Utilities->CallLogPop(1111);
4694  return(true);
4695  }
4696  }
4697  }
4698  Utilities->CallLogPop(1112);
4699  return(false);
4700 }
4701 
4702 // ---------------------------------------------------------------------------
4703 
4704 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4705 {
4706  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4707  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4708  Utilities->CallLogPop(480);
4709 }
4710 
4711 // ---------------------------------------------------------------------------
4712 
4714 {
4715  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4716  if(TrackVector.size() == 0)
4717  {
4718  Utilities->CallLogPop(481);
4719  return;
4720  }
4721  for(unsigned int x = 0; x < TrackVector.size(); x++)
4722  {
4723  if(TrackElementAt(1114, x).TrackType == GapJump)
4724  {
4725  if(TrackElementAt(1115, x).Conn[0] > -1) // set
4726  {
4727  if(TrackElementAt(1116, TrackElementAt(1117, x).Conn[0]).TrackType != GapJump)
4728  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4729  {
4730  TrackElementAt(1118, x).Conn[0] = -1;
4731  TrackElementAt(1119, x).ConnLinkPos[0] = -1;
4732  continue; // to next 'x'
4733  }
4734 // here if gap connection is itself a GapJump
4735  if(TrackElementAt(1120, TrackElementAt(1349, x).Conn[0]).Conn[0] != (int)x)
4736  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4737  // if not clear Conns & CLks
4738  {
4739  TrackElementAt(1121, x).Conn[0] = -1;
4740  TrackElementAt(1122, x).ConnLinkPos[0] = -1;
4741  continue; // to next 'x'
4742  }
4743 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4744 // hence no more action needed on these Conns & CLks
4745  }
4746  } // else //gap jump
4747 
4748  } // for x...
4749 // throw Exception("Test Exception");//test
4750  Utilities->CallLogPop(482);
4751 }
4752 
4753 // ---------------------------------------------------------------------------
4754 
4755 void TTrack::ResetSignals(int Caller)
4756 {
4757  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4758  for(unsigned int x = 0; x < TrackVector.size(); x++)
4759  {
4760  if(TrackElementAt(1123, x).TrackType == SignalPost)
4761  {
4762  TrackElementAt(1124, x).Attribute = 0;
4763  TrackElementAt(1514, x).Failed = false;
4764  }
4765  }
4766  FailedSignalsVector.clear();
4767  Utilities->CallLogPop(483);
4768 }
4769 
4770 // ---------------------------------------------------------------------------
4771 
4772 void TTrack::ResetPoints(int Caller)
4773 {
4774  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4775  for(unsigned int x = 0; x < TrackVector.size(); x++)
4776  {
4777  if((TrackElementAt(1125, x).TrackType == Points) && (TrackElementAt(1571, x).Failed))
4778  {
4779  TrackElementAt(1126, x).Attribute = 0;
4780  TrackElementAt(1515, x).Failed = false;
4783  TrackElementAt(1569, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = -1; //added at v2.15.0
4784  TrackElementAt(1570, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 = -1; //added at v2.15.0
4785  }
4786  }
4787  FailedPointsVector.clear();
4788  Utilities->CallLogPop(484);
4789 }
4790 
4791 // ---------------------------------------------------------------------------
4792 
4793 void TTrack::ResetTSRs(int Caller) //added at v2.14.0
4794 {
4795  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetTSRs");
4796  for(unsigned int x = 0; x < TrackVector.size(); x++)
4797  {
4798  if((TrackElementAt(1554, x).TrackType == Simple) && (TrackElementAt(1555, x).Failed))
4799  {
4800  TrackElementAt(1556, x).Failed = false;
4802  TrackElementAt(1573, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = -1; //added at v2.15.0
4803  }
4804  }
4805  TSRVector.clear();
4806  Utilities->CallLogPop(2550);
4807 }
4808 
4809 // ---------------------------------------------------------------------------
4810 
4811 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4812 {
4813  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4814  if(TrackVector.empty())
4815  {
4816  TrackMap.clear();
4817  Utilities->CallLogPop(485);
4818  return(true);
4819  }
4820 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4821  THVPair TrackMapKeyPair;
4822 
4823  NewVector.clear();
4824  TTrackMapIterator TrackMapPtr;
4825 
4826  if(!TrackMap.empty())
4827  {
4828  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4829  {
4830  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4831  }
4832  }
4833  if(NewVector.size() != TrackMap.size())
4834  {
4835  throw Exception("Error - Map & Vector different sizes");
4836  }
4837  unsigned int NonZeroCount = 0;
4838 
4839  for(unsigned int x = 0; x < TrackVector.size(); x++)
4840  {
4841  if(TrackElementAt(1127, x).TrackType != Erase)
4842  {
4843  NonZeroCount++;
4844  }
4845  }
4846  if(NewVector.size() != NonZeroCount)
4847  {
4848  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4849  }
4851  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4852  TTrackMapEntry TrackMapEntry;
4853 
4854  for(unsigned int x = 0; x < TrackVector.size(); x++)
4855  {
4856  TrackMapKeyPair.first = TrackElementAt(1128, x).HLoc;
4857  TrackMapKeyPair.second = TrackElementAt(1129, x).VLoc;
4858  TrackMapEntry.first = TrackMapKeyPair;
4859  TrackMapEntry.second = x;
4860  if(!(TrackMap.insert(TrackMapEntry).second))
4861  {
4862  throw Exception("Error - map insertion failure, TrackVector in error");
4863  }
4864  }
4865 // All track now relocated in TrackVector, reset all Conns & CLks
4866  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4867  {
4868  for(unsigned int y = 0; y < 4; y++)
4869  {
4870  TrackElementAt(1130, x).Conn[y] = -1;
4871  TrackElementAt(1131, x).ConnLinkPos[y] = -1;
4872  }
4873  }
4874  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4875  CheckMapAndTrack(4); // test
4876  CheckMapAndInactiveTrack(4); // test
4877  CheckLocationNameMultiMap(8); // test
4878  if(!ResetGapsFromGapMap(1))
4879  {
4880  Utilities->CallLogPop(489);
4881  return(false);
4882  }
4883  Utilities->CallLogPop(490);
4884  return(true);
4885 }
4886 
4887 // ---------------------------------------------------------------------------
4888 
4889 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4890 {
4891  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4892  GapMap.clear();
4893  THVPair GapMapKeyPair, GapMapValuePair;
4894  TGapMapEntry GapMapEntry;
4895 
4896  for(unsigned int x = 0; x < TrackVector.size(); x++)
4897  {
4898  if(TrackElementAt(1132, x).TrackType == GapJump)
4899  {
4900  GapMapKeyPair.first = TrackElementAt(1133, x).HLoc;
4901  GapMapKeyPair.second = TrackElementAt(1134, x).VLoc;
4902  GapMapEntry.first = GapMapKeyPair;
4903  if(TrackElementAt(1135, x).Conn[0] == -1)
4904  {
4905  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4906  }
4907  GapMapValuePair.first = TrackElementAt(7, TrackElementAt(1136, x).Conn[0]).HLoc;
4908  GapMapValuePair.second = TrackElementAt(8, TrackElementAt(1137, x).Conn[0]).VLoc;
4909  GapMapEntry.second = GapMapValuePair;
4910  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4911  {
4912  GapMap.insert(GapMapEntry);
4913  }
4914  }
4915  }
4916  Utilities->CallLogPop(492);
4917 }
4918 
4919 // ---------------------------------------------------------------------------
4920 
4921 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4922 {
4923  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4924 
4925 //1st pass to check track element locations - split into 2 passes at v2.11.1 so positioning checked before linkages, requested by Dan(#4669) 18/12/21 via Discord
4926  LocError = false;
4927  bool TrackElementPositionsOK = true;
4928 
4929  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4930  {
4931  if(TrackElementAt(1138, x).TrackType == Erase) //Erase isn't used any more as a track type
4932  {
4933  continue; // skip blank elements
4934  }
4935 // check footcrossing linkages
4936  if(TrackElementAt(1139, x).TrackType == FootCrossing)
4937  {
4938  if(!CheckFootCrossingLinks(1, TrackElementAt(1140, x)))
4939  {
4940  ShowMessage(
4941  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
4942  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
4943  "can't connect to an underpass or vice versa)");
4944  HLoc = TrackElementAt(1141, x).HLoc;
4945  VLoc = TrackElementAt(1142, x).VLoc;
4946  LocError = true;
4947  Utilities->CallLogPop(493);
4948  return(false);
4949  }
4950  }
4951  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4952  {
4953  if(TrackElementAt(1143, x).Link[y] <= 0)
4954  {
4955  continue; // no link
4956  }
4957  if((TrackElementAt(1144, x).TrackType == Buffers) && (TrackElementAt(1145, x).Config[y] == End))
4958  {
4959  continue; // buffer
4960  }
4961  if(TrackElementAt(1146, x).Config[y] == Gap)
4962  {
4963  continue; // gaps set later from GapMap
4964  }
4965  // get required H & V for track element joining link 'y'
4966  int NewHLoc = TrackElementAt(1437, x).HLoc + LinkHVArray[TrackElementAt(1148, x).Link[y]][0];
4967  int NewVLoc = TrackElementAt(1438, x).VLoc + LinkHVArray[TrackElementAt(1150, x).Link[y]][1];
4968  // find track element if present
4969  bool ConnectionFoundFlag;
4970  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4971  if((TrackElementAt(1151, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4972  {
4973  ShowMessage("Can't have a track element adjacent to a continuation exit");
4974  HLoc = TrackElementAt(1152, x).HLoc;
4975  VLoc = TrackElementAt(1153, x).VLoc;
4976  LocError = true;
4977  if(FinalCall)
4978  {
4979  throw Exception("Error in final track linkage - continuation adjacent to another element");
4980  }
4981  Utilities->CallLogPop(1539);
4982  return(false);
4983  }
4984  if((TrackElementAt(1154, x).TrackType == Continuation) && (TrackElementAt(1155, x).Config[y] == End))
4985  {
4986  continue;
4987  }
4988  if(ConnectionFoundFlag)
4989  {
4990  TrackElementAt(1156, x).Conn[y] = VecPos; //<-- this sets the Conn value
4991  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4992 
4993  bool ExitSignal = false;
4994  if(y < 2) //changed at v2.15.0 as 64 bit version failed at ...Config[1 - y]... (32 bit less strict and let it go)
4995  {
4996  if(TrackElementAt(1157, x).Config[1 - y] == Signal)
4997  {
4998  ExitSignal = true;
4999  }
5000  }
5001  if(ExitSignal && IsLCAtHV(50, TrackElementAt(1158, VecPos).HLoc, TrackElementAt(1350, VecPos).VLoc))
5002  {
5003  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
5004  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
5005  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
5006  TrackElementPositionsOK = false;
5007  }
5008  else if(((TrackElementAt(1159, x).TrackType == Points) || (TrackElementAt(1160, x).TrackType == SignalPost) || (TrackElementAt(1161, x).TrackType == Crossover))
5009  && (TrackElementAt(1162, VecPos).TrackType == Buffers))
5010  {
5011  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
5012  // need room for a train (2 elements) without fouling points or signals
5013  TrackElementPositionsOK = false;
5014  }
5015  else if(((TrackElementAt(1163, x).TrackType == Points) || (TrackElementAt(1164, x).TrackType == SignalPost) || (TrackElementAt(1165, x).TrackType == Crossover) ||
5016  (TrackElementAt(1166, x).TrackType == Bridge)) && (TrackElementAt(1167, VecPos).TrackType == Continuation))
5017  {
5018  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
5019  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
5020  // if continuation next to a signal; also none of these can be a named location, and a continuation can
5021  // be named but needs the adjacent element named too
5022  TrackElementPositionsOK = false;
5023  }
5024  else if((TrackElementAt(1168, x).TrackType == SignalPost) && (TrackElementAt(1169, VecPos).TrackType == SignalPost) &&
5025  (TrackElementAt(1170, x).SpeedTag == TrackElementAt(1171, VecPos).SpeedTag))
5026  {
5027  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
5028  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5029  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5030  TrackElementPositionsOK = false;
5031  }
5032 //removed at v2.15.0 as now have a warning for bridge either side of a signal, see below
5033 /* else if((TrackElementAt(1172, x).Config[y] == Signal) && (TrackElementAt(1173, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
5034  {
5035  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5036  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5037  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5038  TrackElementPositionsOK = false;
5039  }*/
5040  else if((TrackElementAt(1564, x).TrackType == SignalPost) && (TrackElementAt(1565, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage) //added at v2.15.0
5041  {
5042  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5043  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5044  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5045  TrackElementPositionsOK = false;
5046  }
5047  else if(IsLCAtHV(45, TrackElementAt(1174, x).HLoc, TrackElementAt(1175, x).VLoc) && IsLCAtHV(46, TrackElementAt(1176, VecPos).HLoc, TrackElementAt(1177, VecPos).VLoc))
5048  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5049  {
5050  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
5051  TrackElementPositionsOK = false;
5052  }
5053  // if failed then set the invert values for the offending element
5054  if(!TrackElementPositionsOK)
5055  {
5056  HLoc = TrackElementAt(1183, x).HLoc;
5057  VLoc = TrackElementAt(1184, x).VLoc;
5058  LocError = true;
5059  if(FinalCall)
5060  {
5061  throw Exception("Error in track element positions in FinalCall");
5062  }
5063  Utilities->CallLogPop(494);
5064  return(false);
5065  }
5066  }
5067  // no 'else' here, if there's no link then will be picked up in 2nd pass
5068  }
5069  } // for(unsigned int x=0;x<TrackVector.size();x++)
5070 
5071 
5072 //2nd pass - looking for missing connections
5073  LocError = false;
5074  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5075  {
5076  if(TrackElementAt(1439, x).TrackType == Erase) //Erase isn't used any more as a track type
5077  {
5078  continue; // skip blank elements
5079  }
5080  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5081  {
5082  if(TrackElementAt(1440, x).Link[y] <= 0)
5083  {
5084  continue; // no link
5085  }
5086  if((TrackElementAt(1441, x).TrackType == Buffers) && (TrackElementAt(1442, x).Config[y] == End))
5087  {
5088  continue; // buffer
5089  }
5090  if(TrackElementAt(1443, x).Config[y] == Gap)
5091  {
5092  continue; // gaps set later from GapMap
5093  }
5094  if((TrackElementAt(1444, x).TrackType == Continuation) && (TrackElementAt(1445, x).Config[y] == End))
5095  {
5096  continue; //continuation
5097  }
5098  // get required H & V for track element joining link 'y'
5099  int NewHLoc = TrackElementAt(1147, x).HLoc + LinkHVArray[TrackElementAt(1448, x).Link[y]][0];
5100  int NewVLoc = TrackElementAt(1149, x).VLoc + LinkHVArray[TrackElementAt(1449, x).Link[y]][1];
5101  // find track element if present
5102  bool ConnectionFoundFlag;
5103  bool LinkMatchFound = false;
5104  int VecPos = GetVectorPositionFromTrackMap(66, NewHLoc, NewVLoc, ConnectionFoundFlag); //this is the joining element at link 'y'
5105  // if there isn't a connection set the invert values for the offending element
5106  if(ConnectionFoundFlag) //set the ConnLinkPos values
5107  {
5108  for(unsigned int a = 0; a < 4; a++) //links for the joining element at this element's link 'y'
5109  {
5110  if((TrackElementAt(1178, VecPos).Link[a] == (10 - TrackElementAt(1179, x).Link[y])) && (TrackElementAt(1180, VecPos).Config[a] != End) &&
5111  (TrackElementAt(1181, VecPos).Config[a] != Gap))
5112  {
5113  TrackElementAt(1182, x).ConnLinkPos[y] = a; //for points, 'y == 0' and 'y == 2' will be allocated same value for 'a'
5114  LinkMatchFound = true;
5115  break; //can only match 1 so can break
5116  }
5117  }
5118  if(!LinkMatchFound)
5119  {
5120  HLoc = TrackElementAt(1446, x).HLoc;
5121  VLoc = TrackElementAt(1447, x).VLoc;
5122  LocError = true;
5123  if(FinalCall)
5124  {
5125  throw Exception("Error in final track linkage - - no matching link found");
5126  }
5127  Utilities->CallLogPop(495);
5128  return(false);
5129  }
5130  }
5131  else //error
5132  {
5133  HLoc = TrackElementAt(1185, x).HLoc;
5134  VLoc = TrackElementAt(1186, x).VLoc;
5135  LocError = true;
5136  if(FinalCall)
5137  {
5138  throw Exception("Error in final track linkage - connection not found");
5139  }
5140  Utilities->CallLogPop(2443);
5141  return(false);
5142  }
5143  }
5144  }
5145 //end of 2nd pass
5146 
5147  if(FinalCall)
5148  {
5151  }
5152 
5153 // confirmatiory checks that all ok - or throw error
5154  bool ConnErrorFlag = false;
5155 
5156  for(unsigned int x = 0; x < TrackVector.size(); x++)
5157  {
5158  if((TrackElementAt(1187, x).Link[0] > 0) && (TrackElementAt(1188, x).Config[0] != End) && (TrackElementAt(1189, x).Conn[0] == -1))
5159  {
5160  ConnErrorFlag = true;
5161  }
5162  if((TrackElementAt(1190, x).Link[1] > 0) && (TrackElementAt(1191, x).Config[1] != End) && (TrackElementAt(1192, x).Conn[1] == -1))
5163  {
5164  ConnErrorFlag = true;
5165  }
5166  if((TrackElementAt(1193, x).Link[2] > 0) && (TrackElementAt(1194, x).Config[2] != End) && (TrackElementAt(1195, x).Conn[2] == -1))
5167  {
5168  ConnErrorFlag = true;
5169  }
5170  if((TrackElementAt(1196, x).Link[3] > 0) && (TrackElementAt(1197, x).Config[3] != End) && (TrackElementAt(1198, x).Conn[3] == -1))
5171  {
5172  ConnErrorFlag = true;
5173  }
5174  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5175  {
5176  if(TrackElementAt(1199, x).ActiveTrackElementName == "")
5177  {
5178  if((TrackElementAt(1200, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1201, x).StationEntryStopLinkPos2 != -1) ||
5179  (TrackElementAt(1637, x).StationEntryStopLinkPos3 != -1) || (TrackElementAt(1638, x).StationEntryStopLinkPos4 != -1))
5180  {
5181  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5182  }
5183  }
5184  }
5185  }
5186  if(ConnErrorFlag)
5187  {
5188  if(FinalCall)
5189  {
5190  throw Exception("ConnError in LinkTrack - Final");
5191  }
5192  else
5193  {
5194  throw Exception("ConnError in LinkTrack - Precheck");
5195  }
5196  }
5197  bool CLkErrorFlag = false;
5198 
5199  for(unsigned int x = 0; x < TrackVector.size(); x++)
5200  {
5201  if((TrackElementAt(1202, x).Link[0] > 0) && (TrackElementAt(1203, x).Config[0] != End) && (TrackElementAt(1204, x).ConnLinkPos[0] == -1))
5202  {
5203  CLkErrorFlag = true;
5204  }
5205  if((TrackElementAt(1205, x).Link[1] > 0) && (TrackElementAt(1206, x).Config[1] != End) && (TrackElementAt(1207, x).ConnLinkPos[1] == -1))
5206  {
5207  CLkErrorFlag = true;
5208  }
5209  if((TrackElementAt(1208, x).Link[2] > 0) && (TrackElementAt(1209, x).Config[2] != End) && (TrackElementAt(1210, x).ConnLinkPos[2] == -1))
5210  {
5211  CLkErrorFlag = true;
5212  }
5213  if((TrackElementAt(1211, x).Link[3] > 0) && (TrackElementAt(1212, x).Config[3] != End) && (TrackElementAt(1213, x).ConnLinkPos[3] == -1))
5214  {
5215  CLkErrorFlag = true;
5216  }
5217  }
5218 
5219  if(CLkErrorFlag)
5220  {
5221  if(FinalCall)
5222  {
5223  throw Exception("CLkError in LinkTrack - Final");
5224  }
5225  else
5226  {
5227  throw Exception("CLkError in LinkTrack - Precheck");
5228  }
5229  }
5230 
5231 // set element lengths to min of 10m
5232  for(unsigned int x = 0; x < TrackVector.size(); x++)
5233  {
5234  if(TrackElementAt(1214, x).TrackType == Erase)
5235  {
5236  continue; // skip blank elements
5237  }
5238  if((TrackElementAt(1215, x).Length01 < 10) && (TrackElementAt(1435, x).Length01 != -1))
5239  {
5240  TrackElementAt(1216, x).Length01 = 10;
5241  }
5242  if((TrackElementAt(1217, x).Length23 < 10) && (TrackElementAt(1218, x).Length23 != -1))
5243  {
5244  TrackElementAt(1219, x).Length23 = 10;
5245  }
5246  }
5247 
5248  if(FinalCall) // ONLY at FinalCall, no point calling twice
5249  {
5250  CalcHLocMinEtc(3);
5251  }
5252 
5253  Utilities->CallLogPop(497);
5254  return(true);
5255 }
5256 
5257 // ---------------------------------------------------------------------------
5258 
5259 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
5260 {
5261  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
5262  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5263  {
5264  if(TrackElementAt(1220, x).TrackType == Erase)
5265  {
5266  continue; // skip blank elements
5267 
5268  }
5269 // check footcrossing linkages
5270  if(TrackElementAt(1221, x).TrackType == FootCrossing)
5271  {
5272  if(!CheckFootCrossingLinks(3, TrackElementAt(1222, x)))
5273  {
5274  Utilities->CallLogPop(1127);
5275  return(false);
5276  }
5277  }
5278  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5279  {
5280  if(TrackElementAt(1223, x).Link[y] <= 0)
5281  {
5282  continue; // no link
5283  }
5284  if((TrackElementAt(1224, x).TrackType == Buffers) && (TrackElementAt(1225, x).Config[y] == End))
5285  {
5286  continue; // buffer
5287  }
5288  if(TrackElementAt(1226, x).Config[y] == Gap)
5289  {
5290  continue; // gaps set later from GapMap
5291 
5292  }
5293  // get required H & V for track element joining link 'y'
5294  int NewHLoc = TrackElementAt(1227, x).HLoc + LinkHVArray[TrackElementAt(1228, x).Link[y]][0];
5295  int NewVLoc = TrackElementAt(1229, x).VLoc + LinkHVArray[TrackElementAt(1230, x).Link[y]][1];
5296  // find track element if present
5297  bool ConnectionFoundFlag;
5298  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5299  if((TrackElementAt(1231, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5300  {
5301  if(FinalCall)
5302  {
5303  throw Exception("Error in final track linkage - continuation adjacent to another element");
5304  }
5305  Utilities->CallLogPop(1540);
5306  return(false);
5307  }
5308  if((TrackElementAt(1232, x).TrackType == Continuation) && (TrackElementAt(1233, x).Config[y] == End))
5309  {
5310  continue;
5311  }
5312  if(ConnectionFoundFlag)
5313  {
5314  TrackElementAt(1234, x).Conn[y] = VecPos;
5315  bool LinkFoundFlag = false;
5316  // find connecting link in the newly found track element if there is one & make checks
5317  if(((TrackElementAt(1235, x).TrackType == Points) || (TrackElementAt(1236, x).TrackType == SignalPost) || (TrackElementAt(1237, x).TrackType == Crossover)) &&
5318  (TrackElementAt(1238, VecPos).TrackType == Buffers))
5319  {
5320  Utilities->CallLogPop(1541);
5321  return(false);
5322  }
5323  else if(((TrackElementAt(1239, x).TrackType == Points) || (TrackElementAt(1240, x).TrackType == SignalPost) || (TrackElementAt(1241, x).TrackType == Crossover) ||
5324  (TrackElementAt(1242, x).TrackType == Bridge)) && (TrackElementAt(1243, VecPos).TrackType == Continuation))
5325  {
5326  Utilities->CallLogPop(1542);
5327  return(false);
5328  }
5329  else if((TrackElementAt(1244, x).TrackType == SignalPost) && (TrackElementAt(1245, VecPos).TrackType == SignalPost) &&
5330  (TrackElementAt(1246, x).SpeedTag == TrackElementAt(1247, VecPos).SpeedTag))
5331  {
5332  Utilities->CallLogPop(1543);
5333  return(false);
5334  }
5335  else if(IsLCAtHV(47, TrackElementAt(1248, x).HLoc, TrackElementAt(1249, x).VLoc) && IsLCAtHV(48, TrackElementAt(1250, VecPos).HLoc, TrackElementAt(1251, VecPos).VLoc))
5336  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5337  {
5338  Utilities->CallLogPop(1981);
5339  return(false);
5340  }
5341 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5342  else if(TrackElementAt(, x).TrackType == Continuation)
5343  {
5344  int H = TrackElementAt(, x).HLoc;
5345  int V = TrackElementAt(, x).VLoc;
5346  bool FoundFlag = false;
5347  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5348  if(FoundFlag)
5349  {
5350  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5351  {
5352  int NewH = TrackElementAt(, (TrackElementAt(, x).Conn[1])).HLoc;
5353  int NewV = TrackElementAt(, (TrackElementAt(, x).Conn[1])).VLoc;
5354  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5355  if(FoundFlag)
5356  {
5357  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5358  {
5359  Utilities->CallLogPop();
5360  return false;
5361  }
5362  }
5363  else
5364  {
5365  Utilities->CallLogPop();
5366  return false;
5367  }
5368  }
5369  }
5370  }
5371 */
5372  for(unsigned int a = 0; a < 4; a++)
5373  {
5374  if((TrackElementAt(1252, VecPos).Link[a] == (10 - TrackElementAt(1253, x).Link[y])) && (TrackElementAt(1254, VecPos).Config[a] != End) &&
5375  (TrackElementAt(1255, VecPos).Config[a] != Gap))
5376  {
5377  TrackElementAt(1256, x).ConnLinkPos[y] = a;
5378  // note - this ensures that if the connecting element is a leading point
5379  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5380  // (Points have the same link value for both [0] and [2])
5381  LinkFoundFlag = true;
5382  break; // stop after first find or will find later link for leading point
5383  }
5384  }
5385  if(!LinkFoundFlag)
5386  {
5387  if(FinalCall)
5388  {
5389  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5390  }
5391  Utilities->CallLogPop(1128);
5392  return(false);
5393  }
5394  }
5395  else // if(ConnectionFoundFlag)
5396  {
5397  if(FinalCall)
5398  {
5399  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5400  }
5401  Utilities->CallLogPop(1129);
5402  return(false);
5403  }
5404  }
5405  } // for(unsigned int x=0;x<TrackVector.size();x++)
5406 
5407  if(FinalCall)
5408  {
5411  }
5412 // final check
5413  bool ConnErrorFlag = false;
5414 
5415  for(unsigned int x = 0; x < TrackVector.size(); x++)
5416  {
5417  if((TrackElementAt(1257, x).Link[0] > 0) && (TrackElementAt(1258, x).Config[0] != End) && (TrackElementAt(1259, x).Conn[0] == -1))
5418  {
5419  ConnErrorFlag = true;
5420  }
5421  if((TrackElementAt(1260, x).Link[1] > 0) && (TrackElementAt(1261, x).Config[1] != End) && (TrackElementAt(1262, x).Conn[1] == -1))
5422  {
5423  ConnErrorFlag = true;
5424  }
5425  if((TrackElementAt(1263, x).Link[2] > 0) && (TrackElementAt(1264, x).Config[2] != End) && (TrackElementAt(1265, x).Conn[2] == -1))
5426  {
5427  ConnErrorFlag = true;
5428  }
5429  if((TrackElementAt(1266, x).Link[3] > 0) && (TrackElementAt(1267, x).Config[3] != End) && (TrackElementAt(1268, x).Conn[3] == -1))
5430  {
5431  ConnErrorFlag = true;
5432  }
5433  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5434  {
5435  if(TrackElementAt(1269, x).ActiveTrackElementName == "")
5436  {
5437  if((TrackElementAt(1270, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1271, x).StationEntryStopLinkPos2 != -1) ||
5438  (TrackElementAt(1639, x).StationEntryStopLinkPos3 != -1) || (TrackElementAt(1640, x).StationEntryStopLinkPos4 != -1))
5439  {
5440  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5441  }
5442  }
5443  }
5444  }
5445  if(ConnErrorFlag)
5446  {
5447  if(FinalCall)
5448  {
5449  throw Exception("ConnError in LinkTrack - Final");
5450  }
5451  else
5452  {
5453  throw Exception("ConnError in LinkTrack - Precheck");
5454  }
5455  }
5456  bool CLkErrorFlag = false;
5457 
5458  for(unsigned int x = 0; x < TrackVector.size(); x++)
5459  {
5460  if((TrackElementAt(1272, x).Link[0] > 0) && (TrackElementAt(1273, x).Config[0] != End) && (TrackElementAt(1274, x).ConnLinkPos[0] == -1))
5461  {
5462  CLkErrorFlag = true;
5463  }
5464  if((TrackElementAt(1275, x).Link[1] > 0) && (TrackElementAt(1276, x).Config[1] != End) && (TrackElementAt(1277, x).ConnLinkPos[1] == -1))
5465  {
5466  CLkErrorFlag = true;
5467  }
5468  if((TrackElementAt(1278, x).Link[2] > 0) && (TrackElementAt(1279, x).Config[2] != End) && (TrackElementAt(1280, x).ConnLinkPos[2] == -1))
5469  {
5470  CLkErrorFlag = true;
5471  }
5472  if((TrackElementAt(1281, x).Link[3] > 0) && (TrackElementAt(1282, x).Config[3] != End) && (TrackElementAt(1283, x).ConnLinkPos[3] == -1))
5473  {
5474  CLkErrorFlag = true;
5475  }
5476  }
5477 
5478  if(CLkErrorFlag)
5479  {
5480  if(FinalCall)
5481  {
5482  throw Exception("CLkError in LinkTrack - Final");
5483  }
5484  else
5485  {
5486  throw Exception("CLkError in LinkTrack - Precheck");
5487  }
5488  }
5489 // set element lengths to min of 10m
5490  for(unsigned int x = 0; x < TrackVector.size(); x++)
5491  {
5492  if(TrackElementAt(1284, x).TrackType == Erase)
5493  {
5494  continue; // skip blank elements
5495  }
5496  if((TrackElementAt(1285, x).Length01 < 10) && (TrackElementAt(1436, x).Length23 != -1))
5497  {
5498  TrackElementAt(1286, x).Length01 = 10;
5499  }
5500  if((TrackElementAt(1287, x).Length23 < 10) && (TrackElementAt(1288, x).Length23 != -1))
5501  {
5502  TrackElementAt(1289, x).Length23 = 10;
5503  }
5504  }
5505 
5506  if(FinalCall) // ONLY at FinalCall, no point calling twice
5507  {
5508  CalcHLocMinEtc(7);
5509  }
5510  Utilities->CallLogPop(1130);
5511  return(true);
5512 }
5513 
5514 // ---------------------------------------------------------------------------
5515 
5516 bool TTrack::IsTrackLinked(int Caller) // not used any more
5517 {
5518  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5519  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5520  {
5521  if(TrackElementAt(1290, x).TrackType == Erase)
5522  {
5523  Utilities->CallLogPop(498);
5524  return(false);
5525  }
5526 // check foot linkages
5527  if(TrackElementAt(1291, x).TrackType == FootCrossing)
5528  {
5529  if(!CheckFootCrossingLinks(2, TrackElementAt(1292, x)))
5530  {
5531  Utilities->CallLogPop(499);
5532  return(false);
5533  }
5534  }
5535  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5536  {
5537  if(TrackElementAt(1293, x).Link[y] <= 0)
5538  {
5539  continue; // no link
5540  }
5541  if(TrackElementAt(1294, x).Config[y] == End)
5542  {
5543  continue; // buffer or continuation
5544  }
5545  if(TrackElementAt(1295, x).Config[y] == Gap)
5546  {
5547  continue; // gaps set later from GapMap
5548 
5549  }
5550  // get required H & V for track element joining link 'y'
5551  int NewHLoc = TrackElementAt(1296, x).HLoc + LinkHVArray[TrackElementAt(1297, x).Link[y]][0];
5552  int NewVLoc = TrackElementAt(1298, x).VLoc + LinkHVArray[TrackElementAt(1299, x).Link[y]][1];
5553  // find track element if present
5554  bool ConnectionFoundFlag = false;
5555  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5556  if(ConnectionFoundFlag)
5557  {
5558  TrackElementAt(1300, x).Conn[y] = VecPos;
5559  // find connecting link in the newly found track element if there is one & make buffer check
5560  bool LinkFoundFlag = false;
5561  if(((TrackElementAt(1301, x).TrackType == Points) || (TrackElementAt(1302, x).TrackType == SignalPost) || (TrackElementAt(1303, x).TrackType == Crossover)) &&
5562  (TrackElementAt(1304, VecPos).TrackType == Buffers))
5563  {
5564  Utilities->CallLogPop(500);
5565  return(false);
5566  }
5567  else if((TrackElementAt(1305, x).TrackType == SignalPost) && (TrackElementAt(1306, VecPos).TrackType == SignalPost) &&
5568  (TrackElementAt(1307, x).SpeedTag == TrackElementAt(1308, VecPos).SpeedTag))
5569  {
5570  Utilities->CallLogPop(501);
5571  return(false);
5572  }
5573  else if((TrackElementAt(1309, x).TrackType == SignalPost) && (TrackElementAt(1310, VecPos).TrackType == Continuation))
5574  {
5575  Utilities->CallLogPop(502);
5576  return(false);
5577  }
5578  else
5579  {
5580  for(unsigned int a = 0; a < 4; a++)
5581  {
5582  if((TrackElementAt(1311, VecPos).Link[a] == (10 - TrackElementAt(1312, x).Link[y])) && (TrackElementAt(1313, VecPos).Config[a] != End) &&
5583  (TrackElementAt(1314, VecPos).Config[a] != Gap))
5584  {
5585  TrackElementAt(1315, x).ConnLinkPos[y] = a;
5586  // note - this ensures that if the connecting element is a leading point
5587  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5588  // (Points have the same link value for both [0] and [2])
5589  LinkFoundFlag = true;
5590  break; // stop after first find or will find later link for leading point
5591  }
5592  }
5593  }
5594  if(!LinkFoundFlag)
5595  {
5596  Utilities->CallLogPop(503);
5597  return(false);
5598  }
5599  }
5600  else // if(ConnectionFoundFlag)
5601  {
5602  Utilities->CallLogPop(504);
5603  return(false);
5604  }
5605  }
5606  } // for(unsigned int x=0;x<TrackVector.size();x++)
5607 
5608 // final check
5609  bool ConnErrorFlag = false;
5610 
5611  for(unsigned int x = 0; x < TrackVector.size(); x++)
5612  {
5613  if((TrackElementAt(1316, x).Link[0] > 0) && (TrackElementAt(1317, x).Config[0] != End) && (TrackElementAt(1318, x).Conn[0] == -1))
5614  {
5615  ConnErrorFlag = true;
5616  }
5617  if((TrackElementAt(1319, x).Link[1] > 0) && (TrackElementAt(1320, x).Config[1] != End) && (TrackElementAt(1321, x).Conn[1] == -1))
5618  {
5619  ConnErrorFlag = true;
5620  }
5621  if((TrackElementAt(1322, x).Link[2] > 0) && (TrackElementAt(1333, x).Config[2] != End) && (TrackElementAt(1334, x).Conn[2] == -1))
5622  {
5623  ConnErrorFlag = true;
5624  }
5625  if((TrackElementAt(1335, x).Link[3] > 0) && (TrackElementAt(1336, x).Config[3] != End) && (TrackElementAt(1337, x).Conn[3] == -1))
5626  {
5627  ConnErrorFlag = true;
5628  }
5629  }
5630  if(ConnErrorFlag)
5631  {
5632  Utilities->CallLogPop(505);
5633  return(false);
5634  }
5635  bool CLkErrorFlag = false;
5636 
5637  for(unsigned int x = 0; x < TrackVector.size(); x++)
5638  {
5639  if((TrackElementAt(1338, x).Link[0] > 0) && (TrackElementAt(1339, x).Config[0] != End) && (TrackElementAt(1340, x).ConnLinkPos[0] == -1))
5640  {
5641  CLkErrorFlag = true;
5642  }
5643  if((TrackElementAt(1341, x).Link[1] > 0) && (TrackElementAt(1342, x).Config[1] != End) && (TrackElementAt(1343, x).ConnLinkPos[1] == -1))
5644  {
5645  CLkErrorFlag = true;
5646  }
5647  if((TrackElementAt(1344, x).Link[2] > 0) && (TrackElementAt(1345, x).Config[2] != End) && (TrackElementAt(1346, x).ConnLinkPos[2] == -1))
5648  {
5649  CLkErrorFlag = true;
5650  }
5651  if((TrackElementAt(1347, x).Link[3] > 0) && (TrackElementAt(1394, x).Config[3] != End) && (TrackElementAt(1348, x).ConnLinkPos[3] == -1))
5652  {
5653  CLkErrorFlag = true;
5654  }
5655  }
5656 
5657  if(CLkErrorFlag)
5658  {
5659  Utilities->CallLogPop(506);
5660  return(false);
5661  }
5662  Utilities->CallLogPop(507);
5663  return(true);
5664 }
5665 
5666 // ---------------------------------------------------------------------------
5667 
5669 {
5670  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5671  int Position1, Position2;
5672  TTrackElement TrackElement1, TrackElement2;
5673  TGapMapIterator GapMapPtr;
5674 
5675  if(!GapMap.empty())
5676  {
5677  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5678  {
5679  int HLoc1 = GapMapPtr->first.first;
5680  int VLoc1 = GapMapPtr->first.second;
5681  int HLoc2 = GapMapPtr->second.first;
5682  int VLoc2 = GapMapPtr->second.second;
5683  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5684  {
5685  throw Exception("Failed to find H & V for gap1, GapMap in error");
5686  }
5687  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5688  {
5689  throw Exception("Failed to find H & V for gap2, GapMap in error");
5690  }
5691  if(TrackElementAt(9, Position1).TrackType != GapJump)
5692  {
5693  throw Exception("Element at Pos1 not a gap, GapMap in error");
5694  }
5695  if(TrackElementAt(10, Position2).TrackType != GapJump)
5696  {
5697  throw Exception("Element at Pos2 not a gap, GapMap in error");
5698  }
5699  TrackElementAt(11, Position1).Conn[0] = Position2;
5700  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5701  TrackElementAt(13, Position2).Conn[0] = Position1;
5702  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5703  }
5704  }
5705  Utilities->CallLogPop(510);
5706  return(true);
5707 }
5708 
5709 // ---------------------------------------------------------------------------
5710 
5711 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5712 {
5713 // TIMPair MapEntry;
5714  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5715  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5716  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5717  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5718  TLocationNameMultiMapEntry LocationNameEntry;
5719 
5720  LocationNameEntry.first = TrackElement.LocationName;
5721  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5722  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5723  {
5724 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5725 // could arise when loading old railways with multiple NonStationNamedLocs
5726  bool FoundFlag = false;
5727  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5728  if(FoundFlag)
5729  {
5730  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5731  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5732  {
5733  Utilities->CallLogPop(1813);
5734  return;
5735  }
5736  }
5737  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5738  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5739  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5740  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5741  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5742  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5743  if(TrackElement.FixedNamedLocationElement)
5744  {
5745  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5746  LocationNameMultiMap.insert(LocationNameEntry);
5747  }
5748  if(TrackElement.HLoc < HLocMin)
5749  {
5750  HLocMin = TrackElement.HLoc;
5751  }
5752  if(TrackElement.HLoc > HLocMax)
5753  {
5754  HLocMax = TrackElement.HLoc;
5755  }
5756  if(TrackElement.VLoc < VLocMin)
5757  {
5758  VLocMin = TrackElement.VLoc;
5759  }
5760  if(TrackElement.VLoc > VLocMax)
5761  {
5762  VLocMax = TrackElement.VLoc;
5763  }
5764  }
5765  else
5766  {
5767 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5768 // shouldn't arise but leave in as a safeguard
5769  bool FoundFlag = false;
5770  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5771  if(FoundFlag)
5772  {
5773  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5774  {
5775  Utilities->CallLogPop(1814);
5776  return;
5777  }
5778  }
5779  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5780  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5781  {
5782  TrackMapKeyPair.first = TrackElement.HLoc;
5783  TrackMapKeyPair.second = TrackElement.VLoc;
5784  TrackMapEntry.first = TrackMapKeyPair;
5785  TrackMapEntry.second = TrackVector.size() - 1;
5786  TrackMap.insert(TrackMapEntry);
5787  if(TrackElement.FixedNamedLocationElement)
5788  {
5789  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5790  LocationNameMultiMap.insert(LocationNameEntry);
5791  }
5792  if(TrackElement.HLoc < HLocMin)
5793  {
5794  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5795  }
5796  if(TrackElement.HLoc > HLocMax)
5797  {
5798  HLocMax = TrackElement.HLoc;
5799  }
5800  if(TrackElement.VLoc < VLocMin)
5801  {
5802  VLocMin = TrackElement.VLoc;
5803  }
5804  if(TrackElement.VLoc > VLocMax)
5805  {
5806  VLocMax = TrackElement.VLoc;
5807  }
5808  }
5809  }
5810 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5811 // CheckMapAndInactiveTrack(6);//test
5812 
5813 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5814 // with the Platforms until layout fully loaded
5815  Utilities->CallLogPop(511);
5816 }
5817 
5818 // ---------------------------------------------------------------------------
5819 
5820 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5821 {
5822  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5823  AnsiString(VLoc));
5824  THVPair TrackMapKeyPair;
5825 
5826  FoundFlag = false;
5827  TTrackMapIterator TrackMapPtr;
5828 
5829  TrackMapKeyPair.first = HLoc;
5830  TrackMapKeyPair.second = VLoc;
5831  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5832  if(TrackMapPtr == TrackMap.end())
5833  {
5834  Utilities->CallLogPop(512);
5835  return(-1); // nothing found
5836  }
5837  else
5838  {
5839  FoundFlag = true;
5840  Utilities->CallLogPop(513);
5841  return(TrackMapPtr->second);
5842  }
5843 }
5844 
5845 // ---------------------------------------------------------------------------
5846 
5847 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5848 {
5849  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5850  AnsiString(VLoc));
5851  THVPair TrackMapKeyPair;
5852  TTrackMapIterator TrackMapPtr;
5853 
5854  TrackMapKeyPair.first = HLoc;
5855  TrackMapKeyPair.second = VLoc;
5856  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5857  if(TrackMapPtr == TrackMap.end())
5858  {
5859  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5860  throw Exception(Message);
5861  }
5862  else
5863  {
5864  Utilities->CallLogPop(1943);
5865  return(TrackElementAt(871, TrackMapPtr->second));
5866  }
5867 }
5868 
5869 // ---------------------------------------------------------------------------
5870 
5871 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector) //new at v2.9.0 for clipboard pref dirs
5872 { //modded at v2.9.2 to make Map & Vector references
5873  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5874  AnsiString(VLoc));
5875  THVPair MapKeyPair;
5876  TTrackMapIterator MapPtr;
5877 
5878  MapKeyPair.first = HLoc;
5879  MapKeyPair.second = VLoc;
5880  MapPtr = Map.find(MapKeyPair);
5881  if(MapPtr == Map.end())
5882  {
5883  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5884  throw Exception(Message);
5885  }
5886  else
5887  {
5888  Utilities->CallLogPop(2280);
5889  return(Vector.at(MapPtr->second));
5890  }
5891 }
5892 
5893 // ---------------------------------------------------------------------------
5894 
5896 {
5897  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5898  AnsiString(VLoc));
5899  THVPair InactiveTrackMapKeyPair;
5900  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5901 
5902  InactiveTrackMapKeyPair.first = HLoc;
5903  InactiveTrackMapKeyPair.second = VLoc;
5904  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5905  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5906  {
5907  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5908  throw Exception(Message);
5909  }
5910  else
5911  {
5912  Utilities->CallLogPop(1949);
5913  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5914  }
5915 }
5916 
5917 // ---------------------------------------------------------------------------
5918 
5919 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5920 {
5921  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5922  bool Present = true;
5923  THVPair TrackMapKeyPair;
5924  TTrackMapIterator TrackMapPtr;
5925 
5926  TrackMapKeyPair.first = HLoc;
5927  TrackMapKeyPair.second = VLoc;
5928  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5929  if(TrackMapPtr == TrackMap.end())
5930  {
5931  Present = false;
5932  }
5933  Utilities->CallLogPop(2057);
5934  return(Present);
5935 }
5936 
5937 // ---------------------------------------------------------------------------
5938 
5939 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5940 {
5941  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5942  AnsiString(VLoc));
5943  bool Present = true;
5944  THVPair InactiveTrackMapKeyPair;
5945  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5946 
5947  InactiveTrackMapKeyPair.first = HLoc;
5948  InactiveTrackMapKeyPair.second = VLoc;
5949  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5950  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5951  {
5952  Present = false;
5953  }
5954  Utilities->CallLogPop(2058);
5955  return(Present);
5956 }
5957 
5958 // ---------------------------------------------------------------------------
5959 
5960 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5961 // max number of elements is 2, for platforms
5962 // note that both elements of RetPair may be the same, if only one present in map
5963 {
5964  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5965  AnsiString(VLoc));
5966  THVPair InactiveTrackMapKeyPair;
5967  TIMPair RetPair;
5968  TInactiveTrackRange InactiveTrackRange;
5969 
5970  FoundFlag = false;
5971  InactiveTrackMapKeyPair.first = HLoc;
5972  InactiveTrackMapKeyPair.second = VLoc;
5973  if(InactiveTrack2MultiMap.empty())
5974  {
5975  RetPair.first = 0;
5976  RetPair.second = 0;
5977  Utilities->CallLogPop(1815);
5978  return(RetPair); // map empty
5979  }
5980  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5981  if(InactiveTrackRange.first == InactiveTrackRange.second)
5982  {
5983  RetPair.first = 0;
5984  RetPair.second = 0;
5985  Utilities->CallLogPop(514);
5986  return(RetPair); // nothing found
5987  }
5988  else
5989  {
5990  RetPair.first = InactiveTrackRange.first->second;
5991  RetPair.second = (--InactiveTrackRange.second)->second;
5992  FoundFlag = true;
5993  Utilities->CallLogPop(515);
5994  return(RetPair);
5995  }
5996 }
5997 
5998 // ---------------------------------------------------------------------------
5999 
6000 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition) //changed at v2.13.0 to return true for failed but matching points
6001 {
6002 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
6003  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
6004  AnsiString(DivergingPosition));
6005  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
6006  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
6007  int SpeedTag1 = T1.SpeedTag;
6008  int SpeedTag2 = T2.SpeedTag;
6009 
6010  if((T1.Attribute) != (T2.Attribute))
6011  {
6012  Utilities->CallLogPop(516);
6013  return(false);
6014  }
6015  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
6016  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
6017  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
6018  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
6019  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
6020  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
6021  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
6022  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
6023  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
6024  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
6025  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
6026  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
6027  {
6028  Utilities->CallLogPop(517);
6029  return(true);
6030  }
6031  else
6032  {
6033  Utilities->CallLogPop(518);
6034  return(false);
6035  }
6036 }
6037 
6038 // ---------------------------------------------------------------------------
6039 
6040 /*
6041  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
6042  {
6043  if(lower.second < higher.second) return true;
6044  else if(lower.second > higher.second) return false;
6045  else if(lower.second == higher.second)
6046  {
6047  if(lower.first < higher.first) return true;
6048  }
6049  return false;
6050  }
6051 */
6052 // ---------------------------------------------------------------------------
6053 
6054 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6055 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
6056 {
6057  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
6058  if(TrackElement.TrackType != GapJump)
6059  {
6060  throw Exception("Error, Wrong track type in PlotGap");
6061  }
6062  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
6063  {
6064  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
6065  }
6066  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
6067  {
6068  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
6069  }
6070  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
6071  {
6072  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
6073  }
6074  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
6075  {
6076  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
6077  }
6078  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
6079  {
6080  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
6081  }
6082  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
6083  {
6084  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
6085  }
6086  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
6087  {
6088  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
6089  }
6090  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
6091  {
6092  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
6093  }
6094  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
6095  {
6096  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
6097  }
6098  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
6099  {
6100  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
6101  }
6102  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
6103  {
6104  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
6105  }
6106  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
6107  {
6108  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
6109  }
6110  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
6111  {
6112  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
6113  }
6114  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
6115  {
6116  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
6117  }
6118  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
6119  {
6120  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
6121  }
6122  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
6123  {
6124  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
6125  }
6126  Utilities->CallLogPop(1101);
6127 }
6128 
6129 // ---------------------------------------------------------------------------
6130 
6131 void TTrack::PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp) //added for multiplayer to add overlays where coupled
6132 {
6133  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotContinuation," + TrackElement.LogTrack(1));
6134  TrackElement.PlotVariableTrackElement(7, Disp);
6135  if(!MultiplayerOverlayMap.empty()) //if it is empty then no overlays needed [map of key = THVPair, value = graphic pointer]
6136  {
6137  THVPair PosPair;
6138  PosPair.first = TrackElement.HLoc;
6139  PosPair.second = TrackElement.VLoc;
6140  TMultiplayerOverlayMap::iterator MOMIt = MultiplayerOverlayMap.find(PosPair);
6141  if(MOMIt != MultiplayerOverlayMap.end()) //if it is then no overlay is needed
6142  {
6143  Disp->PlotOutput(283, TrackElement.HLoc * 16, TrackElement.VLoc * 16, MOMIt->second);
6144  }
6145  }
6146  Utilities->CallLogPop(2403);
6147 }
6148 
6149 // ---------------------------------------------------------------------------
6150 
6151 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
6152 {
6153  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
6154  if(TrackElement.TrackType != Points)
6155  {
6156  throw Exception("Error, Wrong track type in PlotPoints");
6157  }
6158  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
6159  //check if a blue location and if so plot the blue element again - named or not as appropriate - added at v2.18.0 for blue locs at points
6160  bool FoundFlag = false;
6161  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(32, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6162  if(IMPair.first > 0) //can only have one entry in IMPair for points
6163  {
6164  TTrackElement ITE = InactiveTrackElementAt(1409, IMPair.first);
6165  if(ITE.SpeedTag == 131)
6166  {
6167  ITE.PlotVariableTrackElement(8, Disp); //plot the blue square again
6168  }
6169  }
6170  TrackElement.PlotVariableTrackElement(4, Disp);
6171  if(BothFillets)
6172  {
6173  if(TrackElement.SpeedTag < 28)
6174  {
6175  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
6176  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
6177  }
6178  else if(TrackElement.SpeedTag < 132)
6179  {
6180  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
6181  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
6182  }
6183  else
6184  {
6185  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
6186  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
6187  }
6188  }
6189  else if(!TrackElement.Failed) //not failed
6190  {
6191  if(TrackElement.SpeedTag < 28)
6192  {
6193  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6194  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6195  }
6196  else if(TrackElement.SpeedTag < 132)
6197  {
6198  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6199  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6200  }
6201  else
6202  {
6203  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6204  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6205  }
6206  }
6207  else //failed in fixed position
6208  {
6209  if(TrackElement.SpeedTag < 28)
6210  {
6211  Disp->PlotOutput(284, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6212  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6213  }
6214  else if(TrackElement.SpeedTag < 132)
6215  {
6216  Disp->PlotOutput(285, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6217  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6218  }
6219  else
6220  {
6221  Disp->PlotOutput(286, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6222  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6223  }
6224  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6225  }
6226 // replot platform if required
6227  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6228  bool BlueLoc = false;
6229  if(FoundFlag)
6230  {
6231  TTrackElement TE = GetInactiveTrackElementFromTrackMap(6, TrackElement.HLoc, TrackElement.VLoc);
6232  if(TE.SpeedTag == 131) //non-station named location - don't want to replot these added at v2.18.0
6233  {
6234  BlueLoc = true;
6235  }
6236  }
6237  if(FoundFlag && !BlueLoc)
6238  {
6239  // only one platform possible at points so only need to plot IMPair.first
6240  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
6241  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
6242  }
6243  Utilities->CallLogPop(519);
6244 }
6245 
6246 // ---------------------------------------------------------------------------
6247 
6248 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6249 {
6250 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
6251  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
6252  if(TrackElement.TrackType != SignalPost)
6253  {
6254  throw Exception("Error, Wrong track type in PlotSignal");
6255  }
6256  if(!TrackElement.Failed) //added at v2.13.0
6257  {
6258  for(int x = 0; x < 40; x++)
6259  {
6260  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
6261  {
6262  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6263  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6264  // in case existing signal is a double yellow
6265  // plot platforms if present
6266  // Graphics::TBitmap* SignalPlatformGraphic;
6267  // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
6268  // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
6269  // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
6270  // to not be plotted with the above function.
6271  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6272  // now plot signal (double yellow overwrites most of signal platform if present)
6273  // additions at version 0.6 for other aspects & ground sigs
6274  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
6275  {
6276  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
6277  }
6278  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
6279  {
6280  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
6281  }
6282  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
6283  {
6284  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6285  }
6286  else // 4 aspect
6287  {
6288  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
6289  }
6290  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
6291  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
6292  {
6293  if(TrackElement.SpeedTag == 68)
6294  {
6295  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
6296  }
6297  if(TrackElement.SpeedTag == 69)
6298  {
6299  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
6300  }
6301  if(TrackElement.SpeedTag == 70)
6302  {
6303  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
6304  }
6305  if(TrackElement.SpeedTag == 71)
6306  {
6307  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
6308  }
6309  if(TrackElement.SpeedTag == 72)
6310  {
6311  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
6312  }
6313  if(TrackElement.SpeedTag == 73)
6314  {
6315  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
6316  }
6317  if(TrackElement.SpeedTag == 74)
6318  {
6319  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
6320  }
6321  if(TrackElement.SpeedTag == 75)
6322  {
6323  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
6324  }
6325  }
6326  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
6327  // ground signal calling on, need to use normal proceed aspect
6328  {
6329  for(int x = 0; x < 40; x++)
6330  {
6331  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
6332  {
6333  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6334  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6335  // plot special signal platform if present
6336  Graphics::TBitmap* SignalPlatformGraphic;
6337  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
6338  // now plot signal
6339  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6340  }
6341  }
6342  }
6343  break;
6344  }
6345  }
6346  }
6347  else //failed added at v2.13.0
6348  {
6349  if(TrackElement.SigAspect != TTrackElement::GroundSignal)
6350  {
6351  for(int x = 0; x < 8; x++)
6352  {
6353  if(FailedSigTable[x].SpeedTag == TrackElement.SpeedTag)
6354  {
6355  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6356  Disp->PlotSignalBlank(2, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6357  PlotSignalPlatforms(2, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6358  Disp->PlotOutput(287, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedSigTable[x].SigPtr);
6359  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6360  break;
6361  }
6362  }
6363  }
6364  else
6365  {
6366  for(int x = 0; x < 8; x++)
6367  {
6368  if(FailedGroundSigTable[x].SpeedTag == TrackElement.SpeedTag)
6369  {
6370  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6371  Disp->PlotSignalBlank(3, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6372  PlotSignalPlatforms(3, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6373  Disp->PlotOutput(288, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedGroundSigTable[x].SigPtr);
6374  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6375  break;
6376  }
6377  }
6378  }
6379  }
6380  Utilities->CallLogPop(520);
6381 }
6382 
6383 // ---------------------------------------------------------------------------
6384 
6385 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6386 {
6387  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6388  bool FoundFlag;
6389  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6390 
6391  if(!FoundFlag)
6392  {
6393  Utilities->CallLogPop(2112);
6394  return;
6395  }
6396  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6397  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6398 
6399  // don't want 'else if' for the below as may need to plot 2 platforms
6400  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6401  {
6402  if(IAElement1.LocationName == "") // '2' will be same
6403  {
6404  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6405  }
6406  else
6407  {
6408  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6409  }
6410  }
6411  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6412  {
6413  if(IAElement1.LocationName == "") // '2' will be same
6414  {
6415  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6416  }
6417  else
6418  {
6419  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6420  }
6421  }
6422  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6423  {
6424  if(IAElement1.LocationName == "") // '2' will be same
6425  {
6426  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6427  }
6428  else
6429  {
6430  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6431  }
6432  }
6433  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6434  {
6435  if(IAElement1.LocationName == "") // '2' will be same
6436  {
6437  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6438  }
6439  else
6440  {
6441  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6442  }
6443  }
6444  Utilities->CallLogPop(2113);
6445 }
6446 
6447 // ---------------------------------------------------------------------------
6448 
6449 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6450 {
6451 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6452  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6453  AnsiString(VLoc));
6454 // find topmost LC, opening them all (to trains) in turn
6455  int UpStep = 0;
6456 
6457  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6458  {
6459  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6460  UpStep--;
6461  }
6462 // now find bottommost LC, opening them all (to trains) in turn
6463  int DownStep = 1;
6464 
6465  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6466  {
6467  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6468  DownStep++;
6469  }
6470 // find leftmost LC, opening them all (to trains) in turn
6471  int LeftStep = 0;
6472 
6473  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6474  {
6475  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6476  LeftStep--;
6477  }
6478 // now find rightmost LC, opening them all (to trains) in turn
6479  int RightStep = 1;
6480 
6481  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6482  {
6483  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6484  RightStep++;
6485  }
6486  Utilities->CallLogPop(1915);
6487 }
6488 
6489 // ---------------------------------------------------------------------------
6490 
6491 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6492 {
6493  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6494 // work upwards setting all to manual
6495  int UpStep = -1;
6496 
6497  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6498  {
6499  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6500  UpStep--;
6501  }
6502 // work downwards setting all to manual
6503  int DownStep = 1;
6504 
6505  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6506  {
6507  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6508  DownStep++;
6509  }
6510 // work leftwards setting all to manual
6511  int LeftStep = -1;
6512 
6513  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6514  {
6515  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6516  LeftStep--;
6517  }
6518 // work rightwards setting all to manual
6519  int RightStep = 1;
6520 
6521  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6522  {
6523  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6524  RightStep++;
6525  }
6526  Utilities->CallLogPop(2242);
6527 }
6528 
6529 // ---------------------------------------------------------------------------
6530 
6531 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6532 {
6533  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6534  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6535  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6536  {
6537  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6538  {
6539  BarriersDownVector.at(x).TypeOfRoute = 2;
6540  break;
6541  }
6542  }
6543  Utilities->CallLogPop(2243);
6544 }
6545 
6546 // ---------------------------------------------------------------------------
6547 
6548 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6549 {
6550  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6551 // work upwards
6552  int UpStep = 0; //start with this location
6553 
6554  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6555  {
6556  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6557  {
6558  Utilities->CallLogPop(2244);
6559  return(true);
6560  }
6561  UpStep--;
6562  }
6563 // work downwards
6564  int DownStep = 1;
6565 
6566  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6567  {
6568  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6569  {
6570  Utilities->CallLogPop(2245);
6571  return(true);
6572  }
6573  DownStep++;
6574  }
6575 // work leftwards
6576  int LeftStep = -1;
6577 
6578  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6579  {
6580  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6581  {
6582  Utilities->CallLogPop(2246);
6583  return(true);
6584  }
6585  LeftStep--;
6586  }
6587 // work rightwards
6588  int RightStep = 1;
6589 
6590  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6591  {
6592  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6593  {
6594  Utilities->CallLogPop(2247);
6595  return(true);
6596  }
6597  RightStep++;
6598  }
6599  Utilities->CallLogPop(2248);
6600  return(false);
6601 }
6602 
6603 // ---------------------------------------------------------------------------
6604 
6605 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6606 {
6607  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6608  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6609  {
6610  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6611  {
6612  BDVectorPos = x;
6613  Utilities->CallLogPop(2249);
6614  return(true);
6615  }
6616  }
6617  BDVectorPos = -1;
6618  Utilities->CallLogPop(2250);
6619  return(false);
6620 }
6621 
6622 // ---------------------------------------------------------------------------
6623 
6624 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6625 // open to trains
6626 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6627 {
6628  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6629  AnsiString(VLoc));
6630  if(!IsLCAtHV(4, HLoc, VLoc))
6631  {
6632  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6633  }
6634  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6635  {
6636  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6637  }
6638 // check for adjacent LCs & if so open (to trains)
6639  if(BaseElementSpeedTag == 1) // hor track element
6640  {
6641  // find topmost LC, opening them all (to trains) in turn
6642  int UpStep = 0;
6643  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6644  {
6645  UpStep--;
6646  }
6647  UpStep++;
6648  // now find bottommost LC, opening them all (to trains) in turn
6649  int DownStep = 1;
6650  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6651  {
6652  DownStep++;
6653  }
6654  DownStep--;
6655  // now plot graphics, UpStep is smallest & DownStep largest
6656  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6657  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6658  Graphics::TBitmap *RouteGraphic;
6659  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6660  if(TypeOfRoute == 1)
6661  {
6662  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6663  }
6664  else if(TypeOfRoute == 0)
6665  {
6666  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6667  }
6668  else //manual - no route
6669  {
6670  RouteGraphic = BaseGraphic;
6671  }
6672 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6673 // LinkSigRouteGraphicsPtr[1] ver }
6674 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6675 // LinkNonSigRouteGraphicsPtr[1] ver }
6676 
6677  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6678  {
6679  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6680  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6681  if(!Manual)
6682  {
6683  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6684  }
6685  else
6686  {
6687  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6688  }
6689  }
6690  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6691  {
6692  if(UpStep == 0)
6693  {
6694  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6695  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6696  if(!Manual)
6697  {
6698  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6699  }
6700  else
6701  {
6702  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6703  }
6704  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6705  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6706  if(!Manual)
6707  {
6708  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6709  }
6710  else
6711  {
6712  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6713  }
6714  }
6715  else
6716  {
6717  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6718  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6719  if(!Manual)
6720  {
6721  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6722  }
6723  else
6724  {
6725  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6726  }
6727  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6728  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6729  if(!Manual)
6730  {
6731  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6732  }
6733  else
6734  {
6735  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6736  }
6737  }
6738  }
6739  else // at least one plain graphic
6740  {
6741  if(UpStep == 0)
6742  {
6743  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6744  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6745  if(!Manual)
6746  {
6747  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6748  }
6749  else
6750  {
6751  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6752  }
6753  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6754  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6755  if(!Manual)
6756  {
6757  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6758  }
6759  else
6760  {
6761  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6762  }
6763  }
6764  else if(DownStep == 0)
6765  {
6766  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6767  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6768  if(!Manual)
6769  {
6770  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6771  }
6772  else
6773  {
6774  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6775  }
6776  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6777  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6778  if(!Manual)
6779  {
6780  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6781  }
6782  else
6783  {
6784  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6785  }
6786  }
6787  else
6788  {
6789  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6790  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6791  if(!Manual)
6792  {
6793  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6794  }
6795  else
6796  {
6797  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6798  }
6799  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6800  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6801  if(!Manual)
6802  {
6803  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6804  }
6805  else
6806  {
6807  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6808  }
6809  }
6810  for(int x = (UpStep + 1); x < DownStep; x++)
6811  {
6812  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6813  if(x == 0)
6814  {
6815  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6816  }
6817  else
6818  {
6819  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6820  }
6821  if(!Manual)
6822  {
6823  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6824  }
6825  else
6826  {
6827  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6828  }
6829  }
6830  }
6831  Disp->Update();
6832  Utilities->CallLogPop(1958);
6833  return;
6834  }
6835 
6836  else // ver track element
6837  {
6838  // find leftmost LC, opening them all (to trains) in turn
6839  int LStep = 0;
6840  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6841  {
6842  LStep--;
6843  }
6844  LStep++;
6845  // now find rightmost LC, opening them all (to trains) in turn
6846  int RStep = 1;
6847  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6848  {
6849  RStep++;
6850  }
6851  RStep--;
6852  // now plot graphics, LStep is smallest & RStep largest
6853  Graphics::TBitmap *RouteGraphic;
6854  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6855  if(TypeOfRoute == 1)
6856  {
6857  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6858  }
6859  else if(TypeOfRoute == 0)
6860  {
6861  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6862  }
6863  else //manual
6864  {
6865  RouteGraphic = BaseGraphic;
6866  }
6867 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6868 // LinkSigRouteGraphicsPtr[1] ver }
6869 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6870 // LinkNonSigRouteGraphicsPtr[1] ver }
6871  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6872  {
6873  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6874  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6875  if(!Manual)
6876  {
6877  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6878  }
6879  else
6880  {
6881  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6882  }
6883  }
6884  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6885  {
6886  if(LStep == 0)
6887  {
6888  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6889  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6890  if(!Manual)
6891  {
6892  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6893  }
6894  else
6895  {
6896  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6897  }
6898  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6899  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6900  if(!Manual)
6901  {
6902  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6903  }
6904  else
6905  {
6906  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6907  }
6908  }
6909  else
6910  {
6911  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6912  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6913  if(!Manual)
6914  {
6915  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6916  }
6917  else
6918  {
6919  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6920  }
6921  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6922  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6923  if(!Manual)
6924  {
6925  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6926  }
6927  else
6928  {
6929  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6930  }
6931  }
6932  }
6933  else // at least one plain graphic
6934  {
6935  if(LStep == 0)
6936  {
6937  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6938  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6939  if(!Manual)
6940  {
6941  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6942  }
6943  else
6944  {
6945  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6946  }
6947  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6948  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6949  if(!Manual)
6950  {
6951  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6952  }
6953  else
6954  {
6955  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6956  }
6957  }
6958  else if(RStep == 0)
6959  {
6960  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6961  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6962  if(!Manual)
6963  {
6964  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6965  }
6966  else
6967  {
6968  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6969  }
6970  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6971  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6972  if(!Manual)
6973  {
6974  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6975  }
6976  else
6977  {
6978  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6979  }
6980  }
6981  else
6982  {
6983  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6984  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6985  if(!Manual)
6986  {
6987  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6988  }
6989  else
6990  {
6991  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6992  }
6993  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6994  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6995  if(!Manual)
6996  {
6997  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6998  }
6999  else
7000  {
7001  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7002  }
7003  }
7004  for(int x = (LStep + 1); x < RStep; x++)
7005  {
7006  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7007  if(x == 0)
7008  {
7009  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
7010  }
7011  else
7012  {
7013  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
7014  }
7015  if(!Manual)
7016  {
7017  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7018  }
7019  else
7020  {
7021  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7022  }
7023  }
7024  }
7025  Disp->Update();
7026  Utilities->CallLogPop(1896);
7027  return;
7028  }
7029 }
7030 
7031 // ---------------------------------------------------------------------------
7032 
7033 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
7034 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7035 {
7036  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
7037  AnsiString(HLoc) + "," + AnsiString(VLoc));
7038  if(!IsLCAtHV(29, HLoc, VLoc))
7039  {
7040  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7041  }
7042  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7043  {
7044  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7045  }
7046 // check for adjacent LCs & if so open (to trains)
7047  if(BaseElementSpeedTag == 1) // hor track element
7048  {
7049  // find topmost LC, opening them all (to trains) in turn
7050  int UpStep = 0;
7051  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7052  {
7053  UpStep--;
7054  }
7055  UpStep++;
7056  // now find bottommost LC, opening them all (to trains) in turn
7057  int DownStep = 1;
7058  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
7059  {
7060  DownStep++;
7061  }
7062  DownStep--;
7063  // now plot graphics, UpStep is smallest & DownStep largest
7064  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7065  {
7066  if(!Manual)
7067  {
7068  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
7069  }
7070  else
7071  {
7072  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
7073  }
7074  }
7075  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
7076  {
7077  if(!Manual)
7078  {
7079  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7080  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7081  }
7082  else
7083  {
7084  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7085  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7086  }
7087  }
7088  else // at least one plain graphic
7089  {
7090  if(!Manual)
7091  {
7092  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7093  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7094  for(int x = (UpStep + 1); x < DownStep; x++)
7095  {
7096  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
7097  }
7098  }
7099  else
7100  {
7101  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7102  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7103  for(int x = (UpStep + 1); x < DownStep; x++)
7104  {
7105  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
7106  }
7107  }
7108  }
7109  // set markers
7110  for(int x = UpStep; x <= DownStep; x++)
7111  {
7112  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7113  }
7114  Display->Update();
7115  Utilities->CallLogPop(1944);
7116  return;
7117  }
7118 
7119  else // ver track element
7120  {
7121  // find leftmost LC, opening them all (to trains) in turn
7122  int LStep = 0;
7123  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
7124  {
7125  LStep--;
7126  }
7127  LStep++;
7128  // now find rightmost LC, opening them all (to trains) in turn
7129  int RStep = 1;
7130  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
7131  {
7132  RStep++;
7133  }
7134  RStep--;
7135  // now plot graphics, LStep is smallest & RStep largest
7136  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7137  {
7138  if(!Manual)
7139  {
7140  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
7141  }
7142  else
7143  {
7144  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
7145  }
7146  }
7147  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
7148  {
7149  if(!Manual)
7150  {
7151  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7152  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7153  }
7154  else
7155  {
7156  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7157  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7158  }
7159  }
7160  else // at least one plain graphic
7161  {
7162  if(!Manual)
7163  {
7164  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7165  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7166  for(int x = (LStep + 1); x < RStep; x++)
7167  {
7168  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7169  }
7170  }
7171  else
7172  {
7173  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7174  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7175  for(int x = (LStep + 1); x < RStep; x++)
7176  {
7177  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7178  }
7179  }
7180  }
7181  // set markers
7182  for(int x = LStep; x <= RStep; x++)
7183  {
7184  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
7185  }
7186  Disp->Update();
7187  Utilities->CallLogPop(1945);
7188  return;
7189  }
7190 }
7191 
7192 // ---------------------------------------------------------------------------
7193 
7194 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
7195 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7196 {
7197  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
7198  AnsiString(VLoc));
7199  if(!IsLCAtHV(9, HLoc, VLoc))
7200  {
7201  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
7202  }
7203  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7204  {
7205  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
7206  }
7207 // check for adjacent LCs & if so close (to trains)
7208  if(BaseElementSpeedTag == 1) // hor track element
7209  {
7210  // find topmost LC, closing them all (to trains) in turn
7211  int UpStep = 0;
7212  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7213  {
7214  UpStep--;
7215  }
7216  UpStep++;
7217  // now find bottommost LC, opening them all (to trains) in turn
7218  int DownStep = 1;
7219  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
7220  {
7221  DownStep++;
7222  }
7223  DownStep--;
7224  // now plot graphics, UpStep is smallest & DownStep largest
7225  for(int x = UpStep; x < (DownStep + 1); x++)
7226  {
7227  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
7228  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
7229  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7230  }
7231  Disp->Update();
7232  Utilities->CallLogPop(1959);
7233  return;
7234  }
7235 
7236  else // ver track element
7237  {
7238  // find leftmost LC, closing them all (to trains) in turn
7239  int LStep = 0;
7240  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
7241  {
7242  LStep--;
7243  }
7244  LStep++;
7245  // now find rightmost LC, opening them all (to trains) in turn
7246  int RStep = 1;
7247  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
7248  {
7249  RStep++;
7250  }
7251  RStep--;
7252  // now plot graphics, LStep is smallest & RStep largest
7253  for(int x = LStep; x < (RStep + 1); x++)
7254  {
7255  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7256  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
7257  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7258  }
7259  Disp->Update();
7260  Utilities->CallLogPop(1960);
7261  return;
7262  }
7263 }
7264 
7265 // ---------------------------------------------------------------------------
7266 
7267 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
7268 // closed to trains
7269 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7270 {
7271  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
7272  AnsiString(HLoc) + "," + AnsiString(VLoc));
7273  if(!IsLCAtHV(34, HLoc, VLoc))
7274  {
7275  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7276  }
7277  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7278  {
7279  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7280  }
7281  TTrackElement TE;
7282 
7283 // check for adjacent LCs & if so close (to trains)
7284  if(BaseElementSpeedTag == 1) // hor track element
7285  {
7286  // find topmost LC, closing them all (to trains) in turn
7287  int UpStep = 0;
7288  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7289  {
7290  UpStep--;
7291  }
7292  UpStep++;
7293  // now find bottommost LC, opening them all (to trains) in turn
7294  int DownStep = 1;
7295  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
7296  {
7297  DownStep++;
7298  }
7299  DownStep--;
7300  // now plot graphics, UpStep is smallest & DownStep largest
7301  for(int x = UpStep; x <= DownStep; x++)
7302  {
7303  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7304  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7305  }
7306  Display->Update();
7307  Utilities->CallLogPop(1946);
7308  return;
7309  }
7310 
7311  else // ver track element
7312  {
7313  // find leftmost LC, closing them all (to trains) in turn
7314  int LStep = 0;
7315  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
7316  {
7317  LStep--;
7318  }
7319  LStep++;
7320  // now find rightmost LC, opening them all (to trains) in turn
7321  int RStep = 1;
7322  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
7323  {
7324  RStep++;
7325  }
7326  RStep--;
7327  // now plot graphics, LStep is smallest & RStep largest
7328  for(int x = LStep; x <= RStep; x++)
7329  {
7330  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7331  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
7332  }
7333  Display->Update();
7334  Utilities->CallLogPop(1947);
7335  return;
7336  }
7337 }
7338 
7339 // ---------------------------------------------------------------------------
7340 
7341 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
7342 {
7343  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7344  Graphics::TBitmap *RouteGraphic;
7345  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
7346 
7347  if(BaseElementSpeedTag == 1)
7348  {
7349  if(TypeOfRoute == 1)
7350  {
7351  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
7352  }
7353  else if(TypeOfRoute == 0)
7354  {
7355  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
7356  }
7357  else //manual
7358  {
7359  RouteGraphic = BaseGraphic;
7360  }
7361  if(State == Raising)
7362  {
7363  RouteGraphic = BaseGraphic;
7364  }
7365  }
7366  else
7367  {
7368  BaseGraphic = RailGraphics->gl2;
7369  if(TypeOfRoute == 1)
7370  {
7371  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
7372  }
7373  else if(TypeOfRoute == 0)
7374  {
7375  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
7376  }
7377  else
7378  {
7379  RouteGraphic = BaseGraphic; //manual
7380  }
7381  if(State == Raising)
7382  {
7383  RouteGraphic = BaseGraphic;
7384  }
7385  }
7386  int UpStep = 0;
7387 
7388  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7389  {
7390  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7391  if(UpStep == 0)
7392  {
7393  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7394  }
7395  else
7396  {
7397  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7398  }
7399  UpStep--;
7400  }
7401 // now find bottommost LC, opening them all (to trains) in turn
7402  int DownStep = 1;
7403 
7404  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7405  {
7406  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7407  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7408  DownStep++;
7409  }
7410  int LeftStep = 0;
7411 
7412  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7413  {
7414  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7415  if(LeftStep == 0)
7416  {
7417  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7418  }
7419  else
7420  {
7421  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7422  }
7423  LeftStep--;
7424  }
7425 // now find rightmost LC, opening them all (to trains) in turn
7426  int RightStep = 1;
7427 
7428  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7429  {
7430  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7431  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7432  RightStep++;
7433  }
7434  Disp->Update();
7435  Utilities->CallLogPop(1914);
7436 }
7437 
7438 // ---------------------------------------------------------------------------
7439 
7440 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7441 {
7442 // return false for no LC there, flashing or a closed (to trains) LC
7443  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7444  bool FoundFlag;
7445  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7446 
7447  if(!FoundFlag)
7448  {
7449  Utilities->CallLogPop(1898);
7450  return(false);
7451  }
7452  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7453  {
7454  Utilities->CallLogPop(1899);
7455  return(false);
7456  }
7457  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7458  {
7459  Utilities->CallLogPop(1900);
7460  return(true);
7461  }
7462  Utilities->CallLogPop(1901);
7463  return(false);
7464 }
7465 
7466 // ---------------------------------------------------------------------------
7467 
7468 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7469 {
7470 // return false for no LC there, flashing LC or open (to trains) LC
7471  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7472  bool FoundFlag;
7473  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7474 
7475  if(!FoundFlag)
7476  {
7477  Utilities->CallLogPop(1922);
7478  return(false);
7479  }
7480  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7481  {
7482  Utilities->CallLogPop(1923);
7483  return(false);
7484  }
7485  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7486  {
7487  Utilities->CallLogPop(1924);
7488  return(true);
7489  }
7490  Utilities->CallLogPop(1925);
7491  return(false);
7492 }
7493 
7494 // ---------------------------------------------------------------------------
7495 
7496 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7497 {
7498 // return true for barrier in process of moving
7499  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7500  bool FoundFlag;
7501  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7502 
7503  if(!FoundFlag)
7504  {
7505  Utilities->CallLogPop(1918);
7506  return(false);
7507  }
7508  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7509  {
7510  Utilities->CallLogPop(1919);
7511  return(false);
7512  }
7513  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7514  {
7515  Utilities->CallLogPop(1920);
7516  return(true);
7517  }
7518  Utilities->CallLogPop(1921);
7519  return(false);
7520 }
7521 
7522 // ---------------------------------------------------------------------------
7523 
7524 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7525 {
7526 // return true for an LC at H&V
7527  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7528  bool FoundFlag;
7529  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7530 
7531  if(!FoundFlag)
7532  {
7533  Utilities->CallLogPop(1902);
7534  return(false);
7535  }
7536  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7537  {
7538  Utilities->CallLogPop(1903);
7539  return(false);
7540  }
7541  Utilities->CallLogPop(1904);
7542  return(true);
7543 }
7544 
7545 // ---------------------------------------------------------------------------
7546 
7547 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7548 {
7549  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7550  AnsiString(Attr));
7551  bool FoundFlag;
7552  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7553 
7554  if(!FoundFlag)
7555  {
7556  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7557  }
7558  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7559  {
7560  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7561  }
7562  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7563  Utilities->CallLogPop(1905);
7564  return;
7565 }
7566 
7567 // ---------------------------------------------------------------------------
7568 
7570 {
7571  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7572  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7573  {
7574  TTrackElement InactiveTrackElement = InactiveTrackElementAt(140, x);
7575  if(InactiveTrackElement.TrackType == LevelCrossing)
7576  {
7577  InactiveTrackElementAt(141, x).Attribute = 0;
7578  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7579  }
7580  }
7581  Utilities->CallLogPop(1913);
7582  return;
7583 }
7584 
7585 // ---------------------------------------------------------------------------
7586 
7587 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7588 {
7589 // return true if there is either a route set or being set on any element or a train on any element
7590  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7591  "," + AnsiString(VLoc));
7592 
7593  THVPair TrackMapKeyPair;
7594  TTrack::TTrackMapIterator TrackMapPtr;
7595  int DummyRouteNumber;
7596 
7597  TrainPresent = false;
7598 // find topmost LC, checking each for routes & trains
7599  int UpStep = 0;
7600 
7601  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7602  {
7603  TrackMapKeyPair.first = HLoc;
7604  TrackMapKeyPair.second = VLoc + UpStep;
7605  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7606  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7607  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7608  {
7609  Utilities->CallLogPop(1932);
7610  return(true);
7611  }
7612  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7613  {
7614  TrainPresent = true;
7615  Utilities->CallLogPop(1933);
7616  return(true);
7617  }
7618  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7619  {
7620  Utilities->CallLogPop(2274);
7621  return(true);
7622  }
7623  UpStep--;
7624  }
7625 // now find bottommost LC, opening them all (to trains) in turn
7626  int DownStep = 1;
7627 
7628  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7629  {
7630  TrackMapKeyPair.first = HLoc;
7631  TrackMapKeyPair.second = VLoc + DownStep;
7632  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7633  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7634  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7635  {
7636  Utilities->CallLogPop(1934);
7637  return(true);
7638  }
7639  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7640  {
7641  TrainPresent = true;
7642  Utilities->CallLogPop(1935);
7643  return(true);
7644  }
7645  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7646  {
7647  Utilities->CallLogPop(2275);
7648  return(true);
7649  }
7650  DownStep++;
7651  }
7652 // find leftmost LC
7653  int LeftStep = 0;
7654 
7655  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7656  {
7657  TrackMapKeyPair.first = HLoc + LeftStep;
7658  TrackMapKeyPair.second = VLoc;
7659  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7660  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7661  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7662  {
7663  Utilities->CallLogPop(1936);
7664  return(true);
7665  }
7666  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7667  {
7668  TrainPresent = true;
7669  Utilities->CallLogPop(1937);
7670  return(true);
7671  }
7672  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7673  {
7674  Utilities->CallLogPop(2276);
7675  return(true);
7676  }
7677  LeftStep--;
7678  }
7679 // now find rightmost LC, opening them all (to trains) in turn
7680  int RightStep = 1;
7681 
7682  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7683  {
7684  TrackMapKeyPair.first = HLoc + RightStep;
7685  TrackMapKeyPair.second = VLoc;
7686  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7687  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7688  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7689  {
7690  Utilities->CallLogPop(1938);
7691  return(true);
7692  }
7693  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7694  {
7695  TrainPresent = true;
7696  Utilities->CallLogPop(1939);
7697  return(true);
7698  }
7699  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7700  {
7701  Utilities->CallLogPop(2277);
7702  return(true);
7703  }
7704  RightStep++;
7705  }
7706  Utilities->CallLogPop(1940);
7707  return(false);
7708 }
7709 
7710 // ---------------------------------------------------------------------------
7711 
7712 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7713 {
7714  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7715  for(unsigned int x = 0; x < SearchVector.size(); x++)
7716  {
7717  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7718  {
7719  Utilities->CallLogPop(2278);
7720  return(true);
7721  }
7722  }
7723  Utilities->CallLogPop(2279);
7724  return(false);
7725 }
7726 
7727 // ---------------------------------------------------------------------------
7728 
7729 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7730 {
7731  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7732  AnsiString(HLoc) + "," + AnsiString(VLoc));
7733  if(!IsLCAtHV(60, HLoc, VLoc))
7734  {
7735  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7736  }
7737 
7738 // check for adjacent LCs
7739  // find topmost LC
7740  int UpStep = 0;
7741  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7742  {
7743  UpStep--;
7744  }
7745  UpStep++;
7746  // now find bottommost LC, opening them all (to trains) in turn
7747  int DownStep = 1;
7748  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7749  {
7750  DownStep++;
7751  }
7752  DownStep--;
7753  // now plot graphics, UpStep is smallest & DownStep largest
7754  for(int x = UpStep; x <= DownStep; x++)
7755  {
7756  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7757  }
7758 
7759  // find leftmost LC, closing them all (to trains) in turn
7760  int LStep = 0;
7761  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7762  {
7763  LStep--;
7764  }
7765  LStep++;
7766  // now find rightmost LC, opening them all (to trains) in turn
7767  int RStep = 1;
7768  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7769  {
7770  RStep++;
7771  }
7772  RStep--;
7773  // now plot graphics, LStep is smallest & RStep largest
7774  for(int x = LStep; x <= RStep; x++)
7775  {
7776  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7777  }
7778  Display->Update();
7779  Utilities->CallLogPop(2315);
7780  return;
7781 }
7782 
7783 // ---------------------------------------------------------------------------
7784 
7785 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7786 {
7787  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7788  if(TrackElement.TrackType != Points)
7789  {
7790  throw Exception("Error, Wrong track type in GetFilletGraphic");
7791  }
7792  if(TrackElement.SpeedTag < 28)
7793  {
7794  Utilities->CallLogPop(521);
7795  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7796  }
7797  else if(TrackElement.SpeedTag < 132)
7798  {
7799  Utilities->CallLogPop(522);
7800 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7801  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7802  }
7803  else
7804  {
7805  Utilities->CallLogPop(1537);
7806  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7807  }
7808 }
7809 
7810 // ---------------------------------------------------------------------------
7811 
7813 {
7814  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDsAndFailedPointOrigSpeedLimits");
7815  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7816  {
7817  TrackElementAt(1351, x).TrainIDOnElement = -1;
7820  }
7821  Utilities->CallLogPop(1342);
7822 }
7823 
7824 // ---------------------------------------------------------------------------
7825 
7826 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7827 /*
7828  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7829 */
7830 {
7831  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7832  AnsiString(ScreenPosV));
7833  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7834  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7835 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7836  Utilities->CallLogPop(535);
7837 }
7838 
7839 // ---------------------------------------------------------------------------
7840 
7841 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7842 /*
7843  Converts the screen position to the true (without offsets) position
7844 */
7845 {
7846  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7847  AnsiString(ScreenPosV));
7848  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7849  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7850  Utilities->CallLogPop(536);
7851 }
7852 
7853 // ---------------------------------------------------------------------------
7854 
7855 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7856 {
7857  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7858  AnsiString(VPosTrue));
7859  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7860  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7861  Utilities->CallLogPop(537);
7862 }
7863 
7864 // ---------------------------------------------------------------------------
7865 
7866 void TTrack::CheckMapAndTrack(int Caller) // test
7867 {
7868  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7869  int Zeroes = 0;
7870  bool FoundFlag;
7871 
7872  for(unsigned int a = 0; a < TrackVector.size(); a++)
7873  {
7874  TTrackElement CheckElement = Track->TrackElementAt(1354, a);
7875  if(CheckElement.SpeedTag == 0)
7876  {
7877  Zeroes++; // zeroed elements not saved in map
7878  }
7879  else
7880  {
7881  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7882  if(!FoundFlag)
7883  {
7884  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7885  " in TrackMap, Caller=" + (AnsiString)Caller);
7886  }
7887  if(MapVecPos != (int)a)
7888  {
7889  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7890  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7891  (AnsiString)Caller);
7892  }
7893  }
7894  }
7895  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7896  {
7897  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7898  " Caller=" + (AnsiString)Caller);
7899  }
7900  Utilities->CallLogPop(538);
7901  return;
7902 }
7903 
7904 // ---------------------------------------------------------------------------
7905 
7906 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7907 {
7908  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7909  bool FoundFlag;
7910  TIMPair InactivePair;
7911 
7912  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7913  {
7914  TTrackElement CheckElement = Track->InactiveTrackElementAt(142, a);
7915  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7916  if(!FoundFlag)
7917  {
7918  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7919  " in InactiveMap, Caller=" + (AnsiString)Caller);
7920  }
7921  if((InactivePair.first != a) && (InactivePair.second != a))
7922  {
7923  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7924  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7925  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7926  }
7927  }
7928  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
7929  {
7930  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7931  " Caller=" + (AnsiString)Caller);
7932  }
7933  Utilities->CallLogPop(539);
7934 }
7935 
7936 // ---------------------------------------------------------------------------
7937 
7938 void TTrack::CheckGapMap(int Caller) // test
7939 {
7940  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
7941  int Position1, Position2;
7942  TTrackElement TrackElement1, TrackElement2;
7943  TGapMapIterator GapMapPtr;
7944 
7945  if(!GapMap.empty())
7946  {
7947  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
7948  {
7949  int HLoc1 = GapMapPtr->first.first;
7950  int VLoc1 = GapMapPtr->first.second;
7951  int HLoc2 = GapMapPtr->second.first;
7952  int VLoc2 = GapMapPtr->second.second;
7953  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
7954  {
7955  throw Exception("Failed to find H & V for gap1, GapMap in error");
7956  }
7957  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
7958  {
7959  throw Exception("Failed to find H & V for gap2, GapMap in error");
7960  }
7961  if(TrackElementAt(17, Position1).TrackType != GapJump)
7962  {
7963  throw Exception("Element at Pos1 not a gap, GapMap in error");
7964  }
7965  if(TrackElementAt(18, Position2).TrackType != GapJump)
7966  {
7967  throw Exception("Element at Pos2 not a gap, GapMap in error");
7968  }
7969  }
7970  }
7971  unsigned int GapCount = 0;
7972 
7973  for(unsigned int a = 0; a < TrackVector.size(); a++)
7974  {
7975  TTrackElement CheckElement = Track->TrackElementAt(1355, a);
7976  if(CheckElement.TrackType == GapJump)
7977  {
7978  GapCount++;
7979  }
7980  }
7981  if((GapMap.size() * 2) != GapCount)
7982  {
7983  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
7984  (AnsiString)Caller);
7985  }
7986  Utilities->CallLogPop(540);
7987 }
7988 
7989 // ---------------------------------------------------------------------------
7990 
7991 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
7992 {
7993  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
7994  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
7995  {
7996  if(TrackFinished)
7997  {
7998  throw Exception("Error - TrackFinished with erase element still present");
7999  }
8000  Utilities->CallLogPop(541);
8001  return; // erased element, can't set ID
8002  }
8003  AnsiString IDString;
8004 
8005  if(TrackElement.HLoc < 0)
8006  {
8007  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
8008  }
8009  else
8010  {
8011  IDString = AnsiString(TrackElement.HLoc) + "-";
8012  }
8013  if(TrackElement.VLoc < 0)
8014  {
8015  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
8016  }
8017  else
8018  {
8019  IDString += AnsiString(TrackElement.VLoc);
8020  }
8021  TrackElement.ElementID = IDString;
8022  Utilities->CallLogPop(542);
8023 }
8024 
8025 // ---------------------------------------------------------------------------
8026 
8027 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
8028 {
8029 // e.g. "8-13", "00008-13", "N43-N127", etc
8030  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString," + String); //String was inside " marks, corrected at v2.13.0
8031  int DelimPos;
8032 try //try..catch added at v2.13.0 following Amon Sadler's error file received on 24/03/22, had N-113-5 rather than N113-5
8033  {
8034  for(int x = 1; x < String.Length() + 1; x++)
8035  {
8036  if(String.IsDelimiter("-", x))
8037  {
8038  DelimPos = x;
8039  break;
8040  }
8041  if(x == String.Length())
8042  {
8043  if(GiveMessages)
8044  {
8045  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
8046  }
8047  Utilities->CallLogPop(543);
8048  return(-1);
8049  }
8050  }
8051  if(DelimPos == 1)
8052  {
8053  if(GiveMessages)
8054  {
8055  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
8056  }
8057  Utilities->CallLogPop(544);
8058  return(-1);
8059  }
8060  if(DelimPos == String.Length())
8061  {
8062  if(GiveMessages)
8063  {
8064  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
8065  }
8066  Utilities->CallLogPop(545);
8067  return(-1);
8068  }
8069  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
8070  {
8071  if(GiveMessages)
8072  {
8073  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
8074  }
8075  Utilities->CallLogPop(1508);
8076  return(-1);
8077  }
8078  int HLoc, VLoc;
8079 
8080  if(String.SubString(1, 1) != "N")
8081  {
8082  for(int x = 1; x < DelimPos; x++)
8083  {
8084  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8085  {
8086  if(GiveMessages)
8087  {
8088  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8089  }
8090  Utilities->CallLogPop(546);
8091  return(-1);
8092  }
8093  }
8094  }
8095  if(String.SubString(1, 1) == "N")
8096  {
8097  for(int x = 2; x < DelimPos; x++)
8098  {
8099  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8100  {
8101  if(GiveMessages)
8102  {
8103  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8104  }
8105  Utilities->CallLogPop(763);
8106  return(-1);
8107  }
8108  }
8109  }
8110  if(String.SubString(1, 1) == "N")
8111  {
8112  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
8113  }
8114  else
8115  {
8116  HLoc = String.SubString(1, DelimPos - 1).ToInt();
8117  }
8118  if(String.SubString(DelimPos + 1, 1) != "N")
8119  {
8120  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
8121  {
8122  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8123  {
8124  if(GiveMessages)
8125  {
8126  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8127  }
8128  Utilities->CallLogPop(547);
8129  return(-1);
8130  }
8131  }
8132  }
8133  if(String.SubString(DelimPos + 1, 1) == "N")
8134  {
8135  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
8136  {
8137  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8138  {
8139  if(GiveMessages)
8140  {
8141  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8142  }
8143  Utilities->CallLogPop(764);
8144  return(-1);
8145  }
8146  }
8147  }
8148  if(String.SubString(DelimPos + 1, 1) == "N")
8149  {
8150  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
8151  }
8152  else
8153  {
8154  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
8155  }
8156  THVPair HVPair(HLoc, VLoc);
8157  TTrackMapIterator TrackMapPtr;
8158 
8159  TrackMapPtr = TrackMap.find(HVPair);
8160  if(TrackMapPtr == TrackMap.end())
8161  {
8162  if(GiveMessages)
8163  {
8164  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
8165  }
8166  Utilities->CallLogPop(548);
8167  return(-1);
8168  }
8169  Utilities->CallLogPop(549);
8170  return(TrackMapPtr->second);
8171  }
8172  catch(const Exception &e) //non-error catch - catches any errors not already caught above
8173  //(added at v2.13.0 following Amon Sadler's error file received on 24/03/22), had N-113-5 rather than N113-5
8174  {
8175  ShowMessage("Syntax error in track element identifier: <" + String + ">");
8176  Utilities->CallLogPop(2481);
8177  return(-1);
8178  }
8179 }
8180 
8181 // ---------------------------------------------------------------------------
8182 
8183 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
8184 /*
8185  True for linked properly at both ends
8186 */
8187 {
8188  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
8189  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
8190  int HLoc = TrackElement.HLoc;
8191  int VLoc = TrackElement.VLoc;
8192 
8193  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
8194  {
8195  Utilities->CallLogPop(1821);
8196  return(false);
8197  }
8198  if(TrackElement.SpeedTag == 129) // vertical footbridge
8199  {
8200  // check top connection
8201  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
8202  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
8203  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
8204  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
8205  {
8206  Utilities->CallLogPop(550);
8207  return(false);
8208  }
8209  // check bottom connection
8210  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
8211  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
8212  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
8213  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
8214  {
8215  Utilities->CallLogPop(551);
8216  return(false);
8217  }
8218  }
8219  if(TrackElement.SpeedTag == 145) // vertical underpass
8220  {
8221  // check top connection
8222  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
8223  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
8224  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
8225  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
8226  {
8227  Utilities->CallLogPop(2114);
8228  return(false);
8229  }
8230  // check bottom connection
8231  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
8232  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
8233  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
8234  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
8235  {
8236  Utilities->CallLogPop(2115);
8237  return(false);
8238  }
8239  }
8240  if(TrackElement.SpeedTag == 130) // hor footbridge
8241  {
8242  // check left connection
8243  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
8244  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
8245  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
8246  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
8247  {
8248  Utilities->CallLogPop(552);
8249  return(false);
8250  }
8251  // check right connection
8252  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
8253  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
8254  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
8255  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
8256  {
8257  Utilities->CallLogPop(553);
8258  return(false);
8259  }
8260  }
8261  if(TrackElement.SpeedTag == 146) // hor u'pass
8262  {
8263  // check left connection
8264  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
8265  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
8266  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
8267  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
8268  {
8269  Utilities->CallLogPop(2116);
8270  return(false);
8271  }
8272  // check right connection
8273  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
8274  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
8275  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
8276  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
8277  {
8278  Utilities->CallLogPop(2117);
8279  return(false);
8280  }
8281  }
8282  Utilities->CallLogPop(554);
8283  return(true);
8284 }
8285 
8286 // ---------------------------------------------------------------------------
8287 
8288 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8289 /*
8290  return true if the SpeedTag present in the map at H & V
8291 */
8292 {
8293  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8294  AnsiString(SpeedTag));
8295  if(InactiveTrack2MultiMap.empty())
8296  {
8297  Utilities->CallLogPop(555);
8298  return(false);
8299  }
8300  THVPair HVPair(HLoc, VLoc);
8302  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
8303  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
8304 
8305  if(HVRange.first == HVRange.second)
8306  {
8307  Utilities->CallLogPop(556);
8308  return(false);
8309  }
8310  else
8311  {
8312  HVIt1 = HVRange.first;
8313  }
8314  TTrackElement Temp1, Temp2; // test
8315 
8316  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
8317  if(--HVRange.second != HVRange.first)
8318  {
8319  HVIt2 = HVRange.second;
8320  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
8321  }
8322  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
8323  HVIt2->second).SpeedTag == SpeedTag)))
8324  {
8325  Utilities->CallLogPop(557);
8326  return(true);
8327  }
8328  else
8329  {
8330  Utilities->CallLogPop(558);
8331  return(false);
8332  }
8333 }
8334 
8335 // ---------------------------------------------------------------------------
8336 
8337 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8338 /*
8339  return true if the SpeedTag present in the map at H & V
8340 */
8341 {
8342  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8343  AnsiString(SpeedTag));
8344  if(TrackMap.empty())
8345  {
8346  Utilities->CallLogPop(559);
8347  return(false);
8348  }
8349  THVPair HVPair(HLoc, VLoc);
8350  TTrackMapIterator End = TrackMap.end();
8351  TTrackMapIterator It = End;
8352 
8353  It = TrackMap.find(HVPair);
8354  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
8355  {
8356  Utilities->CallLogPop(560);
8357  return(true);
8358  }
8359  else
8360  {
8361  Utilities->CallLogPop(561);
8362  return(false);
8363  }
8364 }
8365 
8366 // ---------------------------------------------------------------------------
8367 
8368 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
8369 {
8370 /*
8371  General:
8372  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
8373  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
8374  a NamedNonStationLocation.
8375  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
8376  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
8377  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
8378  platform at that location).
8379 
8380  Linked named location elements are those explained in TTrack::TTrack()
8381 
8382  Detail:
8383  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
8384  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
8385  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
8386  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
8387  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8388  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8389 
8390  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8391  this function a single element should be in the List (normally from the user's selection but can also be from
8392  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8393  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8394  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8395  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8396  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8397  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8398  moves them into the Map. At the end all linked elements are in the Map.
8399 
8400  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8401  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8402  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8403 */
8404 
8405 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8406 // Display->FileDiagnostics(TestString);//test
8407 
8408  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8409  AnsiString TestString1, TestString2; // test
8410 
8411  Track->LNDone2MultiMap.clear();
8412  if(LNPendingList.size() != 1)
8413  {
8414  throw Exception("LNPendingList size not 1 on entry");
8415  }
8416  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8417  bool FoundFlag = false, ErasedFlag = false;
8418  while(!LNPendingList.empty())
8419  {
8420  CurrentElementNumber = LNPendingList.front();
8421  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8422  int NewElement; // = 2000000000; //marker for unused //not needed from v1.2.0 Beta onwards
8423  int H = CurrentElement->HLoc;
8424  int V = CurrentElement->VLoc;
8425  int Tag = CurrentElement->SpeedTag;
8426  if(Tag == 76) // top plat
8427  {
8428  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8429  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8430  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8431  for(int x = 0; x < 25; x++)
8432  {
8433  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8434  {
8435  LNPendingList.insert(LNPendingList.end(), NewElement);
8436  }
8437  }
8438  }
8439  else if(Tag == 77) // bot plat
8440  {
8441  for(int x = 0; x < 25; x++)
8442  {
8443  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8444  {
8445  LNPendingList.insert(LNPendingList.end(), NewElement);
8446  }
8447  }
8448  }
8449  else if(Tag == 78) // l plat
8450  {
8451  for(int x = 0; x < 25; x++)
8452  {
8453  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8454  {
8455  LNPendingList.insert(LNPendingList.end(), NewElement);
8456  }
8457  }
8458  }
8459  else if(Tag == 79) // r plat
8460  {
8461  for(int x = 0; x < 25; x++)
8462  {
8463  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8464  {
8465  LNPendingList.insert(LNPendingList.end(), NewElement);
8466  }
8467  }
8468  }
8469  else if(Tag == 96) // conc
8470  {
8471  for(int x = 0; x < 28; x++)
8472  {
8473  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8474  {
8475  LNPendingList.insert(LNPendingList.end(), NewElement);
8476  }
8477  }
8478  }
8479  else if(Tag == 129) // vert footbridge
8480  {
8481  for(int x = 0; x < 8; x++)
8482  {
8483  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8484  {
8485  LNPendingList.insert(LNPendingList.end(), NewElement);
8486  }
8487  }
8488  }
8489  else if(Tag == 130) // hor footbridge
8490  {
8491  for(int x = 0; x < 8; x++)
8492  {
8493  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8494  {
8495  LNPendingList.insert(LNPendingList.end(), NewElement);
8496  }
8497  }
8498  }
8499  else if(Tag == 131) // named location
8500  {
8501  for(int x = 0; x < 4; x++)
8502  {
8503  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8504  {
8505  LNPendingList.insert(LNPendingList.end(), NewElement);
8506  }
8507  }
8508  int TVPos = GetVectorPositionFromTrackMap(67, H, V, FoundFlag); //deal with gaps, added at v2.18.0
8509  {
8510  if(FoundFlag && TrackElementAt(1585, TVPos).TrackType == GapJump)
8511  {
8512  int GJTVPos = TrackElementAt(1586, TVPos).Conn[0];
8513  if(GJTVPos > -1)
8514  {
8515  int HLoc = TrackElementAt(1587, GJTVPos).HLoc;
8516  int VLoc = TrackElementAt(1588, GJTVPos).VLoc;
8517  bool FoundFlag2 = false;
8518  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(33, HLoc, VLoc, FoundFlag2);
8519  if(FoundFlag2)
8520  {
8521  if(Track->InactiveTrackElementAt(1410, IMPair.first).SpeedTag == 131) //only need first as second is for platforms
8522  {
8523  if(!ElementInLNDone2MultiMap(5, IMPair.first) && !ElementInLNPendingList(6, IMPair.first))
8524  {
8525  LNPendingList.insert(LNPendingList.end(), IMPair.first);
8526  }
8527  }
8528  }
8529  }
8530  }
8531  }
8532  }
8533  else if(Tag == 145) // v u'pass
8534  {
8535  for(int x = 0; x < 8; x++)
8536  {
8537  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8538  {
8539  LNPendingList.insert(LNPendingList.end(), NewElement);
8540  }
8541  }
8542  }
8543  else if(Tag == 146) // h u'pass
8544  {
8545  for(int x = 0; x < 8; x++)
8546  {
8547  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8548  {
8549  LNPendingList.insert(LNPendingList.end(), NewElement);
8550  }
8551  }
8552  }
8553  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8554 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8555  if(AddingElements)
8556  {
8557  int HPos, VPos; // not used but needed for FindText function
8558  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8559  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8560  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8561  {
8562  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8563  if((ExistingName != "") && (ExistingName != LocationName))
8564  {
8565  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8566  {
8567  } // name not in LocationNameMultiMap, so don't erase from TextVector
8568  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8569  {
8570  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8571  {
8572  ;
8573  } // condition not used
8574 
8575  }
8576  }
8577  }
8578  }
8579  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8580  // track at that loc
8581  THVPair HVPair(H, V);
8582  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8583  LNDone2MultiMapEntry.first = HVPair;
8584  LNDone2MultiMapEntry.second = LNPendingList.front();
8585  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8586  LNPendingList.erase(LNPendingList.begin());
8587  }
8588 
8589 // search all name multimap for same name where corresponding active elements don't appear in
8590 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8591 
8592  TLocationNameMultiMapIterator SNIterator;
8593  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8594 
8595  if(SNRange.first != SNRange.second)
8596  {
8597  SNRange.first--; // now pointing to before the first
8598  SNRange.second--; // now pointing to the last
8599  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8600  {
8601  // Same elements are in Done map as in name map
8602  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8603  {
8604  ErasedFlag = true;
8605  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8606  TVIt->LocationName = "";
8607  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8608  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8609  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8610  {
8611  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8612  if(FoundFlag)
8613  {
8614  TrackElementAt(20, Position).LocationName = "";
8615  TrackElementAt(21, Position).ActiveTrackElementName = "";
8616  }
8617  }
8618  // erase name in name map
8619 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8620  }
8621  }
8622  }
8623  if(ErasedFlag)
8624  {
8626  }
8627  if(TrackFinished)
8628  {
8631  }
8632 // set here as well as in LinkTrack so don't have to link track just because a name added
8633 // if track not finished then will be set when track validated
8634 
8635 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8636 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8637 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8638 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8639 // so the error would be seen.
8640 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8641  std::pair<AnsiString, char>TempMapPair;
8642 
8643  ContinuationNameMap.clear();
8644  for(int x = 0; x < Track->TrackVectorSize(); x++)
8645  {
8646  if((Track->TrackElementAt(1356, x).TrackType == Continuation) && (Track->TrackElementAt(1357, x).ActiveTrackElementName != ""))
8647  {
8648  TempMapPair.first = Track->TrackElementAt(1358, x).ActiveTrackElementName;
8649  TempMapPair.second = 'x'; // unused
8650  ContinuationNameMap.insert(TempMapPair);
8651  }
8652  }
8653 //end of addition
8654  CheckLocationNameMultiMap(1); // test
8655  Utilities->CallLogPop(562);
8656 }
8657 
8658 // ---------------------------------------------------------------------------
8659 
8660 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8661 /*
8662  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8663  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8664 */
8665 {
8666  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8667  AnsiString(SpeedTag));
8668  if(!NamedLocationElementAt(2, HLoc, VLoc))
8669  {
8670  Utilities->CallLogPop(948);
8671  return(false);
8672  }
8673  bool FoundFlag;
8674  int Position = -1;
8675  TIMPair IMPair;
8676 
8677  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8678  {
8679  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8680  if(FoundFlag)
8681  {
8682  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8683  {
8684  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8685  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8686  // don't allow duplicates in either list, or processing takes a lot longer
8687  {
8688  FoundElement = MapPos;
8689  Utilities->CallLogPop(563);
8690  return(true);
8691  }
8692  }
8693  }
8694  }
8695  else
8696  {
8697  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8698  if(FoundFlag)
8699  {
8700  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8701  {
8702  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8703  {
8704  FoundElement = IMPair.first;
8705  Utilities->CallLogPop(564);
8706  return(true);
8707  }
8708  }
8709  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8710  {
8711  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8712  {
8713  FoundElement = IMPair.second;
8714  Utilities->CallLogPop(565);
8715  return(true);
8716  }
8717  }
8718  }
8719  }
8720  Utilities->CallLogPop(566);
8721  return(false);
8722 }
8723 
8724 // ---------------------------------------------------------------------------
8725 
8726 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8727 /*
8728  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8729  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8730  with the new name
8731 */
8732 {
8733  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8734  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8735 
8736  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8737  int HLoc = TrackElement->HLoc;
8738  int VLoc = TrackElement->VLoc;
8739  bool FoundFlag;
8740 
8741  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8742  // only have timetable names for adjacent platforms & named locations
8743  {
8744  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8745  if(FoundFlag)
8746  {
8747  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8748  }
8749  }
8750  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8751 
8752  if(ErrorString != "")
8753  {
8754  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8755  }
8756  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8757  CheckLocationNameMultiMap(2); // test
8758  Utilities->CallLogPop(567);
8759 }
8760 
8761 // ---------------------------------------------------------------------------
8762 
8763 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8764 /*
8765  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8766 */
8767 {
8768  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8769  if(LNDone2MultiMap.empty())
8770  {
8771  Utilities->CallLogPop(568);
8772  return(false);
8773  }
8774  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8775 
8776  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8777  {
8778  if(LNDone2MultiMapIterator->second == MapPos)
8779  {
8780  Utilities->CallLogPop(569);
8781  return(true);
8782  }
8783  }
8784  Utilities->CallLogPop(570);
8785  return(false);
8786 }
8787 
8788 // ---------------------------------------------------------------------------
8789 
8790 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8791 /*
8792  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8793 */
8794 {
8795  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8796  if(LNPendingList.empty())
8797  {
8798  Utilities->CallLogPop(571);
8799  return(false);
8800  }
8801  TLNPendingListIterator LNPendingListIterator;
8802 
8803  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8804  {
8805  if(*LNPendingListIterator == MapPos)
8806  {
8807  Utilities->CallLogPop(572);
8808  return(true);
8809  }
8810  }
8811  Utilities->CallLogPop(573);
8812  return(false);
8813 }
8814 
8815 // ---------------------------------------------------------------------------
8816 
8817 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8818 /*
8819  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8820 */
8821 {
8822  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8823  THVPair HVPair(HLoc, VLoc);
8824  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8825  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8826 
8827  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8828  {
8829  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8830  {
8831  Utilities->CallLogPop(574);
8832  return(true);
8833  }
8834  }
8835  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8836  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8837  {
8838  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8839  {
8840  Utilities->CallLogPop(575);
8841  return(true);
8842  }
8843  }
8844  Utilities->CallLogPop(576);
8845  return(false);
8846 }
8847 
8848 // ---------------------------------------------------------------------------
8849 
8850 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8851 {
8852  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8853  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8854  {
8855  Utilities->CallLogPop(1953);
8856  return(true);
8857  }
8858  Utilities->CallLogPop(1954);
8859  return(false);
8860 }
8861 
8862 // ---------------------------------------------------------------------------
8863 
8864 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8865 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8866 //program and used when try to save as a .rly file
8867 {
8868  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8871  if(LocationNameMultiMap.empty()) //no names so no duplicates
8872  {
8873  Utilities->CallLogPop(2254);
8874  return(false);
8875  }
8876  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8877  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8878  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8879  {
8881  {
8882  if(GiveMessage)
8883  {
8884  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8885  }
8886  Utilities->CallLogPop(2255);
8887  return(true);
8888  }
8889  }
8890  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8891  {
8892  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8893  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8894  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8895  {
8897  {
8898  if(GiveMessage)
8899  {
8900  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8901  }
8902  Utilities->CallLogPop(2256);
8903  return(true);
8904  }
8905  }
8906  }
8907  Utilities->CallLogPop(2257);
8908  return(false); //OK, no duplicates
8909 }
8910 
8911 // ---------------------------------------------------------------------------
8912 
8914 {
8915  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8916  THVPair HVPair;
8917  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8918  //for use in the duplicate check
8919  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8920  {
8921  if(LNMMIt->second < 0) //active track element
8922  {
8923  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8924  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8925  }
8926  else //inactive track element
8927  {
8928  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
8929  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
8930  }
8931  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
8932  }
8933  //All HVPairs now present in HVPairsLinkedMap for the specific location name
8934 
8935  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
8936  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
8937  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
8938 
8939  std::list<THVPair> HVLinkedList;
8940 
8941  //set the first value to true and add it to the list
8942  HVPairsLinkedMap.begin()->second = true;
8943  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
8944  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
8945  //examination
8946  THVPair HVPairUnderExamination;
8947  THVPairsLinkedMap::iterator HVPLMIt;
8948  THVPair HVPairNew;
8949  while(!HVLinkedList.empty())
8950  {
8951  HVPairUnderExamination = HVLinkedList.front();
8952  HVLinkedList.pop_front();
8953  HVPairNew.first = HVPairUnderExamination.first;
8954  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
8955  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8956  if(HVPLMIt != HVPairsLinkedMap.end())
8957  {
8958  if(!HVPLMIt->second)
8959  {
8960  HVLinkedList.push_back(HVPLMIt->first);
8961  }
8962  HVPLMIt->second = true;
8963  }
8964  HVPairNew.first = HVPairUnderExamination.first - 1;
8965  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
8966  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8967  if(HVPLMIt != HVPairsLinkedMap.end())
8968  {
8969  if(!HVPLMIt->second)
8970  {
8971  HVLinkedList.push_back(HVPLMIt->first);
8972  }
8973  HVPLMIt->second = true;
8974  }
8975  HVPairNew.first = HVPairUnderExamination.first;
8976  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
8977  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8978  if(HVPLMIt != HVPairsLinkedMap.end())
8979  {
8980  if(!HVPLMIt->second)
8981  {
8982  HVLinkedList.push_back(HVPLMIt->first);
8983  }
8984  HVPLMIt->second = true;
8985  }
8986  HVPairNew.first = HVPairUnderExamination.first + 1;
8987  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
8988  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8989  if(HVPLMIt != HVPairsLinkedMap.end())
8990  {
8991  if(!HVPLMIt->second)
8992  {
8993  HVLinkedList.push_back(HVPLMIt->first);
8994  }
8995  HVPLMIt->second = true;
8996  }
8997  }
8998 
8999  //at the end if any have a false bool then the name is duplicated so return false
9000  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
9001  {
9002  if(!HVPLMIt->second)
9003  {
9004  Utilities->CallLogPop(2258);
9005  return(false);
9006  }
9007  }
9008  Utilities->CallLogPop(2259);
9009  return(true);
9010 }
9011 
9012 // ---------------------------------------------------------------------------
9013 
9014 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
9015 /*
9016  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
9017 */
9018 
9019 {
9020  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
9021  if(LocationName == "")
9022  {
9023  Utilities->CallLogPop(577);
9024  return(false);
9025  }
9026 // new for v0.2b
9027 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
9029  {
9030  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
9031  ActiveTrackElementNameMap.clear();
9032  for(unsigned int x = 0; x < TrackVector.size(); x++)
9033  {
9034  if((TrackElementAt(1359, x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackElementAt(1360, x).ActiveTrackElementName))
9035  == ContinuationNameMap.end())
9036  {
9037  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
9038  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1361, x).ActiveTrackElementName;
9039  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
9040  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
9041  }
9042  }
9044  }
9045  Utilities->CallLogPop(578);
9046  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
9047 // end of new section
9048 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
9049 }
9050 
9051 // ---------------------------------------------------------------------------
9052 
9053 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
9054 /*
9055  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
9056  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
9057  new names in the vectors.
9058 */
9059 {
9060  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
9061  bool FoundFlag, ErasedFlag = false;
9062  TLocationNameMultiMapIterator SNIterator;
9063  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9064 
9065  if(SNRange.first != SNRange.second)
9066  {
9067  ErasedFlag = true;
9068  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9069  {
9070  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
9071  TVIt->LocationName = "";
9072  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
9073  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
9074  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
9075  {
9076  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
9077  if(FoundFlag)
9078  {
9079  TrackElementAt(25, Position).LocationName = "";
9080  TrackElementAt(26, Position).ActiveTrackElementName = "";
9081  }
9082  }
9083  }
9084  }
9085  if(ErasedFlag)
9086  {
9088  }
9089  CheckLocationNameMultiMap(3); // test
9090  Utilities->CallLogPop(579);
9091 }
9092 
9093 // ---------------------------------------------------------------------------
9094 
9095 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
9096 /*
9097  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
9098  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
9099  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
9100  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during PlotAndAddTrackElement,
9101  to bring the named location and timetable naming up to date with the deletion or insertion. Note that only one name is sought,
9102  it is entered into LNPendingList and EnterLocationName sets all others.
9103 */
9104 {
9105  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
9106  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
9107  LNPendingList.clear();
9108  AnsiString LocationName;
9109  int MapPos;
9110  bool FoundFlag = 0;
9111 
9112 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9113  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
9114  if(FoundFlag)
9115  {
9116  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
9117  if(LocationName != "")
9118  {
9119  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
9120  EnterLocationName(13, LocationName, true);
9121  Utilities->CallLogPop(2251);
9122  return;
9123  }
9124  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
9125  if(LocationName != "")
9126  {
9127  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
9128  EnterLocationName(14, LocationName, true);
9129  Utilities->CallLogPop(2252);
9130  return;
9131  }
9132  }
9133 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9134 
9135  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
9136  if(FoundFlag)
9137  {
9138  LocationName = TrackElementAt(1004, Position).LocationName;
9139  if(LocationName != "")
9140  {
9141  int ModifiedPosition = -1 - Position;
9142  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
9143  EnterLocationName(15, LocationName, true);
9144  Utilities->CallLogPop(2253);
9145  return;
9146  }
9147  }
9148  if(SpeedTag == 76) // top plat
9149  {
9150  for(int x = 0; x < 25; x++)
9151  {
9152  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
9153  {
9154  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9155  EnterLocationName(3, LocationName, true);
9156  break;
9157  }
9158  }
9159  }
9160  else if(SpeedTag == 77) // bot plat
9161  {
9162  for(int x = 0; x < 25; x++)
9163  {
9164  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
9165  {
9166  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9167  EnterLocationName(4, LocationName, true);
9168  break;
9169  }
9170  }
9171  }
9172  else if(SpeedTag == 78) // l plat
9173  {
9174  for(int x = 0; x < 25; x++)
9175  {
9176  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
9177  {
9178  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9179  EnterLocationName(5, LocationName, true);
9180  break;
9181  }
9182  }
9183  }
9184  else if(SpeedTag == 79) // r plat
9185  {
9186  for(int x = 0; x < 25; x++)
9187  {
9188  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
9189  {
9190  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9191  EnterLocationName(6, LocationName, true);
9192  break;
9193  }
9194  }
9195  }
9196  else if(SpeedTag == 96) // conc
9197  {
9198  for(int x = 0; x < 28; x++)
9199  {
9200  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
9201  {
9202  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9203  EnterLocationName(7, LocationName, true);
9204  break;
9205  }
9206  }
9207  }
9208  else if(SpeedTag == 129) // vert footbridge
9209  {
9210  for(int x = 0; x < 8; x++)
9211  {
9212  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
9213  {
9214  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9215  EnterLocationName(8, LocationName, true);
9216  break;
9217  }
9218  }
9219  }
9220  else if(SpeedTag == 130) // hor footbridge
9221  {
9222  for(int x = 0; x < 8; x++)
9223  {
9224  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
9225  {
9226  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9227  EnterLocationName(9, LocationName, true);
9228  break;
9229  }
9230  }
9231  }
9232  else if(SpeedTag == 145) // vert u'pass
9233  {
9234  for(int x = 0; x < 8; x++)
9235  {
9236  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
9237  {
9238  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9239  EnterLocationName(11, LocationName, true);
9240  break;
9241  }
9242  }
9243  }
9244  else if(SpeedTag == 146) // hor u'pass
9245  {
9246  for(int x = 0; x < 8; x++)
9247  {
9248  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
9249  {
9250  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9251  EnterLocationName(12, LocationName, true);
9252  break;
9253  }
9254  }
9255  }
9256  else if(SpeedTag == 131) // named location
9257  {
9258  for(int x = 0; x < 4; x++)
9259  {
9260  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
9261  {
9262  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9263  EnterLocationName(10, LocationName, true);
9264  Utilities->CallLogPop(2657);
9265  return;
9266  }
9267  }
9268  int TVPos = GetVectorPositionFromTrackMap(68, HLoc, VLoc, FoundFlag); //deal with gaps, added at v2.18.0
9269  {
9270  if(FoundFlag && TrackElementAt(1589, TVPos).TrackType == GapJump)
9271  {
9272  int GJTVPos = TrackElementAt(1590, TVPos).Conn[0];
9273  if(GJTVPos > -1)
9274  {
9275  int HLoc2 = TrackElementAt(1591, GJTVPos).HLoc;
9276  int VLoc2 = TrackElementAt(1592, GJTVPos).VLoc;
9277  LocationName = TrackElementAt(1593, GJTVPos).ActiveTrackElementName;
9278  bool FoundFlag2 = false;
9279  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(34, HLoc2, VLoc2, FoundFlag2);
9280  if(FoundFlag2)
9281  {
9282  if(Track->InactiveTrackElementAt(1411, IMPair.first).SpeedTag == 131) //only need first as second is for platforms
9283  {
9284  LNPendingList.insert(LNPendingList.end(), IMPair.first);
9285  EnterLocationName(16, LocationName, true);
9286  }
9287  }
9288  }
9289  }
9290  }
9291  }
9292 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
9293  Utilities->CallLogPop(580);
9294 }
9295 
9296 // ---------------------------------------------------------------------------
9297 
9298 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
9299 /*
9300  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
9301  true if a LocationName is found, and also returns the name and the adjusted vector position.
9302 */
9303 {
9304  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
9305  AnsiString(SpeedTag));
9306  bool FoundFlag;
9307  TIMPair IMPair;
9308  TTrackVectorIterator TempElement;
9309  int Position;
9310 
9311  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
9312  if(FoundFlag)
9313  {
9314  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
9315  {
9316  TempElement = InactiveTrackVector.begin() + IMPair.first;
9317  if(TempElement->LocationName != "")
9318  {
9319  LocationName = TempElement->LocationName;
9320  FoundElement = IMPair.first;
9321  Utilities->CallLogPop(581);
9322  return(true);
9323  }
9324  }
9325  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
9326  {
9327  TempElement = InactiveTrackVector.begin() + IMPair.second;
9328  if(TempElement->LocationName != "")
9329  {
9330  LocationName = TempElement->LocationName;
9331  FoundElement = IMPair.second;
9332  Utilities->CallLogPop(582);
9333  return(true);
9334  }
9335  }
9336  }
9337  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
9338  if(FoundFlag)
9339  {
9340  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
9341  {
9342  TempElement = TrackVector.begin() + Position;
9343  if(TempElement->LocationName != "")
9344  {
9345  LocationName = TempElement->LocationName;
9346  FoundElement = -1 - Position;
9347  Utilities->CallLogPop(583);
9348  return(true);
9349  }
9350  }
9351  }
9352  Utilities->CallLogPop(584);
9353  return(false);
9354 }
9355 
9356 // ---------------------------------------------------------------------------
9357 
9358 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
9359 {
9360 // check quantity in map & vectors match
9361  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
9362  unsigned int Count = 0;
9363 
9364  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
9365  {
9366  Utilities->CallLogPop(2059);
9367  return;
9368  }
9369  AnsiString SName, TName, ErrorString;
9370 
9371  for(unsigned int x = 0; x < TrackVector.size(); x++)
9372  {
9373  if(TrackElementAt(1362, x).FixedNamedLocationElement)
9374  {
9375  if(TrackElementAt(1363, x).TrackType != FootCrossing)
9376  {
9377  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
9378  AnsiString(Caller));
9379  }
9380  Count++;
9381  }
9382  }
9383  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9384  {
9385  if(InactiveTrackElementAt(143, x).FixedNamedLocationElement)
9386  {
9387  if((InactiveTrackElementAt(144, x).TrackType != Platform) && (InactiveTrackElementAt(145, x).TrackType != NamedNonStationLocation) &&
9388  (InactiveTrackElementAt(146, x).TrackType != Concourse))
9389  {
9390  throw Exception
9391  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
9392  AnsiString(Caller));
9393  }
9394  Count++;
9395  }
9396  }
9397  if(LocationNameMultiMap.size() != Count)
9398  {
9399  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
9400  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9401  }
9402 // check all entries in both vectors match entries in name multimap
9404 
9405  for(unsigned int x = 0; x < TrackVector.size(); x++)
9406  {
9407  if(TrackElementAt(1364, x).FixedNamedLocationElement)
9408  {
9409  SName = TrackElementAt(1365, x).LocationName;
9410  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
9411  if(ErrorString != "")
9412  {
9413  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
9414  }
9415  if(SNIt->second != -1 - (int)x)
9416  {
9417  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9418  AnsiString(Caller));
9419  }
9420  }
9421  // check corresponding platform for all Timetable entries that aren't empty
9422  TName = TrackElementAt(1366, x).ActiveTrackElementName;
9423  TIMPair IMPair;
9424  bool FoundFlag = false;
9425  if(TName != "")
9426  {
9427  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackElementAt(1367, x).HLoc, TrackElementAt(1368, x).VLoc, FoundFlag);
9428  if(FoundFlag)
9429  {
9430  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
9432  {
9433  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackElementAt(1369, x).HLoc) + " & V " +
9434  AnsiString(TrackElementAt(1370, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9435  }
9436  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9437  {
9438  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackElementAt(1371, x).HLoc) +
9439  " & V " + AnsiString(TrackElementAt(1372, x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9440  AnsiString(Caller));
9441  }
9442  }
9443  else
9444  {
9445  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackElementAt(1373, x).HLoc) + " & V " +
9446  AnsiString(TrackElementAt(1374, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9447  }
9448  }
9449  }
9450  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9451  {
9452  if(InactiveTrackElementAt(147, x).FixedNamedLocationElement)
9453  {
9454  SName = InactiveTrackElementAt(148, x).LocationName;
9455  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9456  if(ErrorString != "")
9457  {
9458  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9459  }
9460  if(SNIt->second != (int)x)
9461  {
9462  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9463  AnsiString(Caller));
9464  }
9465  }
9466  }
9467  Utilities->CallLogPop(585);
9468 }
9469 
9470 // ---------------------------------------------------------------------------
9471 
9473  AnsiString &ErrorString)
9474 {
9475 /*
9476  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9477  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9478  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9479 */
9480  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9481  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9482  ErrorString = "";
9483  bool FoundFlag = false;
9484  TLocationNameMultiMapIterator SNIterator;
9485  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9486 
9487  if(SNRange.first == SNRange.second)
9488  {
9489  ErrorString = "Error, Name " + LocationName + " not found in map";
9490  Utilities->CallLogPop(586);
9491  return(SNRange.first);
9492  }
9493  else
9494  {
9495  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9496  {
9497  if(SNIterator->second < 0)
9498  {
9499  int TVPos = -1 - SNIterator->second;
9500  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9501  if(TVIt == TrackElement)
9502  {
9503  FoundFlag = true;
9504  Utilities->CallLogPop(587);
9505  return(SNIterator);
9506  }
9507  }
9508  else
9509  {
9510  int ITVPos = SNIterator->second;
9511  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9512  if(ITVIt == TrackElement)
9513  {
9514  FoundFlag = true;
9515  Utilities->CallLogPop(588);
9516  return(SNIterator);
9517  }
9518  }
9519  }
9520  }
9521  if(!FoundFlag)
9522  {
9523  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9524  }
9525  Utilities->CallLogPop(589);
9526  return(SNIterator);
9527 }
9528 
9529 // ---------------------------------------------------------------------------
9530 
9531 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9532 {
9533 /*
9534  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9535  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9536 */
9537  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9538  TLocationNameMultiMapEntry LocationNameEntry;
9539 
9540  LocationNameEntry.first = NewName;
9541  LocationNameEntry.second = SNIterator->second;
9542  LocationNameMultiMap.erase(SNIterator);
9543  LocationNameMultiMap.insert(LocationNameEntry);
9544  Utilities->CallLogPop(590);
9545 }
9546 
9547 // ---------------------------------------------------------------------------
9548 
9550 {
9551 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9552  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9553  if(Position < 0) // footcrossing
9554  {
9555  int TruePos = -1 - Position;
9556  // new check at v0.2b
9557  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9558  {
9559  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9560  }
9561  Utilities->CallLogPop(591);
9562  return (TrackVector.begin() + TruePos);
9563  }
9564  else
9565  {
9566  // new check at v0.2b
9567  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9568  {
9569  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9570  }
9571  Utilities->CallLogPop(592);
9572  return (InactiveTrackVector.begin() + Position);
9573  }
9574 }
9575 
9576 // ---------------------------------------------------------------------------
9577 
9578 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9579 {
9580 /*
9581  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9582  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9583  LocationNameMultiMap.
9584 */
9585  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9586  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9587  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9588 
9589  if(!InactiveTrack2MultiMap.empty())
9590  {
9591  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9592  InactiveTrack2MultiMapIterator++)
9593  {
9594  if(InactiveTrack2MultiMapIterator->second > VecPos)
9595  {
9596  InactiveTrack2MultiMapIterator->second--;
9597  }
9598  // can't be == VecPos as that position erased
9599  }
9600  }
9601  if(!LocationNameMultiMap.empty())
9602  {
9603  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9604  LocationNameMultiMapIterator++)
9605  {
9606  if(LocationNameMultiMapIterator->second < 0)
9607  {
9608  continue; // deal with TrackVectors separately
9609  }
9610  if(LocationNameMultiMapIterator->second > (int)VecPos)
9611  {
9612  LocationNameMultiMapIterator->second--;
9613  }
9614  }
9615  }
9616  Utilities->CallLogPop(593);
9617 }
9618 
9619 // ---------------------------------------------------------------------------
9620 
9621 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9622 {
9623 /*
9624  After an element has been erased from the track vector, all the later elements are moved down one. This function
9625  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9626  LocationNameMultiMap.
9627 */
9628  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9629  TTrackMapIterator TrackMapIterator;
9630  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9631 
9632  if(!TrackMap.empty())
9633  {
9634  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9635  {
9636  if(TrackMapIterator->second > VecPos)
9637  {
9638  TrackMapIterator->second--;
9639  }
9640  // can't be == VecPos as that position erased
9641  }
9642  }
9643  if(!LocationNameMultiMap.empty())
9644  {
9645  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9646  LocationNameMultiMapIterator++)
9647  {
9648  if(LocationNameMultiMapIterator->second >= 0)
9649  {
9650  continue; // deal with InactiveTrackVectors separately
9651  }
9652  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9653  // Val -1 -2 -3 -4 -5 -6 -7 -8
9654  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9655  {
9656  LocationNameMultiMapIterator->second++;
9657  }
9658  }
9659  }
9660  for(unsigned int x = 0; x < TrackVector.size(); x++)
9661  {
9662  TTrackElement &TkEl = TrackElementAt(1375, x); // no need to check so use this to speed up
9663  if(TkEl.TrackType == GapJump)
9664  {
9665  // position 0 is the gap
9666  if(TkEl.Conn[0] == int(VecPos))
9667  {
9668  TkEl.Conn[0] = -1; // connected to a deleted gap
9669  continue;
9670  }
9671  if(TkEl.Conn[0] > int(VecPos))
9672  {
9673  TkEl.Conn[0]--;
9674  }
9675  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9676  {
9677  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9678  {
9679  TkEl.Conn[0] = -1;
9680  }
9681  }
9682  }
9683  }
9684  Utilities->CallLogPop(1433);
9685 }
9686 
9687 // ---------------------------------------------------------------------------
9688 
9690 /*
9691  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9692  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9693  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9694  InactiveTrackvector values are stored as they are, 0 to n, whereas ActiveTrackvector values stored as -1 - TVPos, i.e.
9695  running from -1 to -1 - n
9696 */
9697 {
9698  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9699  LocationNameMultiMap.clear();
9700  TLocationNameMultiMapEntry LocationNameEntry;
9701  TTrackElement TrackElement;
9702 
9703  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9704  {
9705  TrackElement = TrackElementAt(1376, TVPos);
9706  if(TrackElement.FixedNamedLocationElement)
9707  {
9708  LocationNameEntry.first = TrackElement.LocationName;
9709  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9710  LocationNameMultiMap.insert(LocationNameEntry);
9711  }
9712  }
9713 
9714  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9715  {
9716  TrackElement = InactiveTrackElementAt(149, ITVPos);
9717  if(TrackElement.FixedNamedLocationElement)
9718  {
9719  LocationNameEntry.first = TrackElement.LocationName;
9720  LocationNameEntry.second = ITVPos;
9721  LocationNameMultiMap.insert(LocationNameEntry);
9722  }
9723  }
9724  Utilities->CallLogPop(594);
9725 }
9726 
9727 // ---------------------------------------------------------------------------
9728 
9730 // Return true if there is a named location present in the railway
9731 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9732 {
9733  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9734  TTrackVectorIterator ITVI;
9735 
9736  if(InactiveTrackVector.empty())
9737  {
9738  Utilities->CallLogPop(1343);
9739  return(false);
9740  }
9741  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9742  {
9743  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9744  {
9745  Utilities->CallLogPop(1404);
9746  return(true);
9747  }
9748  }
9749  Utilities->CallLogPop(1344);
9750  return(false);
9751 }
9752 
9753 // ---------------------------------------------------------------------------
9754 
9756 /*
9757  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9758 */
9759 {
9760  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9761 // ResetDistanceElements(6);
9762  for(unsigned int x = 0; x < TrackVector.size(); x++)
9763  {
9764  TTrackElement &TE = TrackElementAt(718, x);
9767  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9768  {
9771  }
9772  }
9773 /* old function
9774  if((TrackElementAt(, x).TrackType == Points) || (TrackElementAt(, x).TrackType == Crossover) || (TrackElementAt(, x).TrackType == Bridge))
9775  {
9776  SetOneDefaultTrackLength(2, TrackElementAt(, x), 0);
9777  SetOneDefaultTrackLength(3, TrackElementAt(, x), 2);
9778  }
9779  else
9780  {
9781  SetOneDefaultTrackLength(4, TrackElementAt(, x), 0);
9782  }
9783  }
9784 */
9785  Utilities->CallLogPop(617);
9786 }
9787 
9788 // ---------------------------------------------------------------------------
9789 
9790 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
9791 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
9792 {
9793  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
9794  for(unsigned int x = 0; x < TrackVector.size(); x++)
9795  {
9796  TTrackElement TempElement = TrackElementAt(1377, x);
9797  if(TempElement.Length01 > -1)
9798  {
9799  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9800  }
9801  if(TempElement.Length23 > -1)
9802  {
9803  MarkOneLength(2, TempElement, false, Disp);
9804  }
9805  }
9806  Disp->Update();
9807  Utilities->CallLogPop(618);
9808 }
9809 
9810 // ---------------------------------------------------------------------------
9811 
9812 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
9813 /*
9814  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h normally but can be changed in Config.txt
9815  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
9816  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
9817  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
9818  track as indicated by FirstTrack (true for track01 & false for track23).
9819 */
9820 {
9821  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
9822  AnsiString((short)FirstTrack));
9823  bool LengthDifferent = false, SpeedDifferent = false;
9824 
9825  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
9826  {
9827  Utilities->CallLogPop(619);
9828  return;
9829  }
9830  int EXArray[16][2] =
9831  {{4, 6}, {2, 8}, // horizontal & vertical
9832  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9833  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9834  {1, 9}, {3, 7}}; // forward & reverse diagonals
9835 
9836  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
9837  Graphics::TBitmap *Bitmap;
9838 
9839  if(FirstTrack)
9840  {
9841  InLink = TrackElement.Link[0];
9842  OutLink = TrackElement.Link[1];
9843  }
9844  else
9845  {
9846  InLink = TrackElement.Link[2];
9847  OutLink = TrackElement.Link[3];
9848  }
9849  for(int x = 0; x < 16; x++)
9850  {
9851  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9852  {
9853  Index = x;
9854  }
9855  }
9856  if(Index == -1)
9857  {
9858  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
9859  }
9860 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9861  the graphic for each of which is different because of the shape of the overbridge. The basic
9862  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9863  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9864  int BrEXArray[24][2] = {
9865  {4,6},{2,8},{1,9},{3,7},
9866  {1,9},{3,7},{1,9},{3,7},
9867  {2,8},{4,6},{2,8},{4,6}
9868 */
9869  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9870  {
9871  if(Index == 1)
9872  {
9873  if(TrackElement.SpeedTag == 49)
9874  {
9875  BrNum = 1 + 16;
9876  }
9877  else if(TrackElement.SpeedTag == 54)
9878  {
9879  BrNum = 8 + 16;
9880  }
9881  else if(TrackElement.SpeedTag == 55)
9882  {
9883  BrNum = 10 + 16;
9884  }
9885  }
9886  else if(Index == 0)
9887  {
9888  if(TrackElement.SpeedTag == 48)
9889  {
9890  BrNum = 0 + 16;
9891  }
9892  else if(TrackElement.SpeedTag == 58)
9893  {
9894  BrNum = 11 + 16;
9895  }
9896  else if(TrackElement.SpeedTag == 59)
9897  {
9898  BrNum = 9 + 16;
9899  }
9900  }
9901  else if(Index == 14)
9902  {
9903  if(TrackElement.SpeedTag == 50)
9904  {
9905  BrNum = 2 + 16;
9906  }
9907  else if(TrackElement.SpeedTag == 52)
9908  {
9909  BrNum = 4 + 16;
9910  }
9911  else if(TrackElement.SpeedTag == 57)
9912  {
9913  BrNum = 6 + 16;
9914  }
9915  }
9916  else if(Index == 15)
9917  {
9918  if(TrackElement.SpeedTag == 51)
9919  {
9920  BrNum = 3 + 16;
9921  }
9922  else if(TrackElement.SpeedTag == 53)
9923  {
9924  BrNum = 7 + 16;
9925  }
9926  else if(TrackElement.SpeedTag == 56)
9927  {
9928  BrNum = 5 + 16;
9929  }
9930  }
9931  }
9932  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9933  {
9934  GrNum = BrNum;
9935  }
9936  else
9937  {
9938  GrNum = Index;
9939  }
9940  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
9941  {
9942  if(GrNum > 15) // underbridge
9943  {
9944  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
9945  }
9946  else
9947  {
9948  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
9949  }
9950  if(TrackElement.SpeedTag == 64)
9951  {
9952  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9953  }
9954  if(TrackElement.SpeedTag == 65)
9955  {
9957  }
9958  if(TrackElement.SpeedTag == 66)
9959  {
9961  }
9962  if(TrackElement.SpeedTag == 67)
9963  {
9965  }
9966  if(TrackElement.SpeedTag == 80)
9967  {
9968  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
9969  }
9970  if(TrackElement.SpeedTag == 81)
9971  {
9973  }
9974  if(TrackElement.SpeedTag == 82)
9975  {
9977  }
9978  if(TrackElement.SpeedTag == 83)
9979  {
9981  }
9982  if(TrackElement.SpeedTag == 84)
9983  {
9985  }
9986  if(TrackElement.SpeedTag == 85)
9987  {
9989  }
9990  if(TrackElement.SpeedTag == 86)
9991  {
9993  }
9994  if(TrackElement.SpeedTag == 87)
9995  {
9997  }
9998  if(TrackElement.SpeedTag == 129)
9999  {
10000  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
10001  }
10002  if(TrackElement.SpeedTag == 130)
10003  {
10005  }
10006  }
10007 
10008  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
10009  {
10010  if(GrNum > 15) // underbridge
10011  {
10012  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
10013  }
10014  else
10015  {
10016  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
10017  }
10018  if(TrackElement.SpeedTag == 64)
10019  {
10020  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10021  }
10022  if(TrackElement.SpeedTag == 65)
10023  {
10024  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
10025  }
10026  if(TrackElement.SpeedTag == 66)
10027  {
10028  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
10029  }
10030  if(TrackElement.SpeedTag == 67)
10031  {
10032  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
10033  }
10034  if(TrackElement.SpeedTag == 80)
10035  {
10036  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
10037  }
10038  if(TrackElement.SpeedTag == 81)
10039  {
10040  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
10041  }
10042  if(TrackElement.SpeedTag == 82)
10043  {
10044  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
10045  }
10046  if(TrackElement.SpeedTag == 83)
10047  {
10048  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
10049  }
10050  if(TrackElement.SpeedTag == 84)
10051  {
10052  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
10053  }
10054  if(TrackElement.SpeedTag == 85)
10055  {
10056  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
10057  }
10058  if(TrackElement.SpeedTag == 86)
10059  {
10060  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
10061  }
10062  if(TrackElement.SpeedTag == 87)
10063  {
10064  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
10065  }
10066  if(TrackElement.SpeedTag == 129)
10067  {
10068  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
10069  }
10070  if(TrackElement.SpeedTag == 130)
10071  {
10072  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
10073  }
10074  }
10075 
10076  else // SpeedDifferent only: red - use non sig graphics
10077  {
10078  if(GrNum > 15) // underbridge
10079  {
10080  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
10081  }
10082  else
10083  {
10084  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
10085  }
10086  if(TrackElement.SpeedTag == 64)
10087  {
10088  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10089  }
10090  if(TrackElement.SpeedTag == 65)
10091  {
10093  }
10094  if(TrackElement.SpeedTag == 66)
10095  {
10097  }
10098  if(TrackElement.SpeedTag == 67)
10099  {
10101  }
10102  if(TrackElement.SpeedTag == 80)
10103  {
10104  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
10105  }
10106  if(TrackElement.SpeedTag == 81)
10107  {
10109  }
10110  if(TrackElement.SpeedTag == 82)
10111  {
10113  }
10114  if(TrackElement.SpeedTag == 83)
10115  {
10117  }
10118  if(TrackElement.SpeedTag == 84)
10119  {
10121  }
10122  if(TrackElement.SpeedTag == 85)
10123  {
10125  }
10126  if(TrackElement.SpeedTag == 86)
10127  {
10129  }
10130  if(TrackElement.SpeedTag == 87)
10131  {
10133  }
10134  if(TrackElement.SpeedTag == 129)
10135  {
10136  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
10137  }
10138  if(TrackElement.SpeedTag == 130)
10139  {
10141  }
10142  }
10143  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
10144  Utilities->CallLogPop(620);
10145 }
10146 
10147 // ---------------------------------------------------------------------------
10148 
10149 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
10150 /* FirstTrack = LinkPos's 0 & 1
10151  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
10152 */
10153 {
10154  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
10155  AnsiString((short)FirstTrack));
10156  LengthDifferent = false;
10157  SpeedDifferent = false;
10158  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
10159  {
10160  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10161  {
10162  LengthDifferent = true;
10163  }
10164  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10165  {
10166  SpeedDifferent = true;
10167  }
10168  if(LengthDifferent || SpeedDifferent)
10169  {
10170  Utilities->CallLogPop(625);
10171  return(false);
10172  }
10173  Utilities->CallLogPop(626);
10174  return(true);
10175  }
10176 
10177  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
10178  {
10179  if(TrackElement.Length23 != Utilities->DefaultTrackLength)
10180  {
10181  LengthDifferent = true;
10182  }
10183  if(TrackElement.SpeedLimit23 != Utilities->DefaultTrackSpeedLimit)
10184  {
10185  SpeedDifferent = true;
10186  }
10187  if(LengthDifferent || SpeedDifferent)
10188  {
10189  Utilities->CallLogPop(627);
10190  return(false);
10191  }
10192  Utilities->CallLogPop(628);
10193  return(true);
10194  }
10195 
10196  else // any other 1 track element, including platforms being present
10197  {
10198  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10199  {
10200  LengthDifferent = true;
10201  }
10202  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10203  {
10204  SpeedDifferent = true;
10205  }
10206  if(LengthDifferent || SpeedDifferent)
10207  {
10208  Utilities->CallLogPop(629);
10209  return(false);
10210  }
10211  Utilities->CallLogPop(630);
10212  return(true);
10213  }
10214 }
10215 
10216 // ---------------------------------------------------------------------------
10217 
10218 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10219 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
10220 {
10221  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10222  AnsiString(VLoc));
10223  bool FoundFlag;
10224  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
10225 
10226  if(!FoundFlag)
10227  {
10228  Utilities->CallLogPop(633);
10229  return(false);
10230  }
10231  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
10232  {
10233  Utilities->CallLogPop(634);
10234  return(true); // only need to check first since if second is a platform the the first must be too
10235  }
10236  else
10237  {
10238  Utilities->CallLogPop(635);
10239  return(false);
10240  }
10241 }
10242 
10243 // ---------------------------------------------------------------------------
10244 
10245 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10246 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
10247 {
10248  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10249  AnsiString(VLoc));
10250  bool FoundFlag;
10251  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
10252 
10253  if(!FoundFlag)
10254  {
10255  Utilities->CallLogPop(636);
10256  return(false);
10257  }
10259  {
10260  Utilities->CallLogPop(637);
10261  return(true); // only need to check first since only one used for NamedNonStationLocations
10262  }
10263  else
10264  {
10265  Utilities->CallLogPop(638);
10266  return(false);
10267  }
10268 }
10269 
10270 // ---------------------------------------------------------------------------
10271 
10272 void TTrack::SetStationEntryStopLinkPosses(int Caller) //only for platforms
10273 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
10274  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
10275  the front of train stop points for each direction.
10276  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
10277  end (unless buffers at one or both ends in which case stop points are the end elements).
10278  Note that for a single element the stop point is the element itself (formula doesn't apply).
10279  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
10280  repeating the procedure for every element. At the end all unused values are returned to -1.
10281  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
10282 */
10283 {
10284  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
10285  TTrackElement TempElement, StartElement;
10286  AnsiString TempName;
10287  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
10288  bool ForwardSet, ReverseSet;
10289 
10290  for(unsigned int x = 0; x < TrackVector.size(); x++)
10291  {
10292  TrackElementAt(1378, x).StationEntryStopLinkPos1 = -1; //this only sets 0 & 1 as all single track elements for platforms
10294  }
10295  for(unsigned int x = 0; x < TrackVector.size(); x++)
10296  {
10297  TempElement = TrackElementAt(1380, x);
10298  if(!IsNamedNonStationLocationPresent(2, TempElement.HLoc, TempElement.VLoc)) //deal with non-station names later
10299  {
10300  ForwardSet = false;
10301  ReverseSet = false;
10302  VecPos = x;
10303  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1) && (TempElement.StationEntryStopLinkPos2 == -1))
10304  // 2nd condition incl so don't re-examine elements with stop links set to 5
10305  {
10306  TempName = TempElement.ActiveTrackElementName;
10307  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10308  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10309  // an element linked at both ends where both links are also named elements
10310  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
10311  {
10312  continue; // looking for an end element so skip this one
10313  }
10314  else // reached one end
10315  {
10316  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
10317  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10318  // single named element linked at both ends, can't be continuation as platforms not allowed there
10319  {
10320  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
10321  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
10322  continue;
10323  }
10324  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10325  // single named buffer element (LinkPos 1 is the non-buffer end)
10326  {
10327  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
10328  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
10329  continue;
10330  }
10331  else
10332  // Note: only interested in connection positions 0 & 1 since all platform elements are single track except points,
10333  // and platforms always on straight (conns 0 & 1) section of points
10334  {
10335  for(int y = 0; y < 2; y++)
10336  {
10337  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
10338  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
10339  /* TTrackElement Temp1 = TempElement;
10340  ***********New section, compiles but not checked - does bit below need to be else if?
10341  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
10342  {
10343  //search along Dir direction until find other end, skip if Dir facing buffer end
10344  int NewDir = Dir;
10345  int NewVecPos;
10346  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
10347  {
10348  NewVecPos = Temp1.Conn[NewDir];
10349  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
10350  Temp1 = TrackElementAt(601, NewVecPos);
10351  }
10352  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
10353  {
10354  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
10355  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
10356  }
10357  }
10358  ***************
10359  */
10360  // end may be linked at both ends but only one link named, or buffer with linked element named
10361  // if a buffer then the named linkpos has to be 1
10362  // already dealt with all types of single element so at least 2 linked named elements
10363  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
10364  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
10365  { //element linked at both ends with entry end not same name, or buffers with exit link == 1 (exit link always 1 but need to ensure Dir set correctly)
10366  StartElement = TempElement;
10367  StartVecPos = VecPos; //this stays fixed at start of platform group
10368  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
10369  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
10370  EntryPos = 1 - Dir;
10371  StartEntryPos = 1 - Dir;
10372  Count = 1;
10373  // work along named elements until find the other end
10374  while((TempElement.Conn[1 - EntryPos] > -1) && (TempElement.Conn[1 - EntryPos] < (int)TrackVector.size()) && (TrackElementAt(53, TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
10375  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
10376  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
10377  // all stop link pos's are set to 5
10378  {
10379  VecPos = TempElement.Conn[1 - EntryPos];
10380  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10381  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
10382  EntryPos = TempEntryPos;
10383  Count++;
10384  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
10385  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
10386  }
10387  // here when reached other end, maybe buffers, or last named linked element
10388  if(TrackElementAt(57, VecPos).TrackType == Buffers)
10389  // terminal station, set end elements as stop elements
10390  {
10391  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
10392  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
10393  continue;
10394  }
10395  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
10396  // terminal station, set end elements as stop elements
10397  {
10398  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
10399  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10400  continue;
10401  }
10402  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
10403  ForwardNumber = ((Count + 1) / 2) + 1;
10404  ReverseNumber = (Count - ForwardNumber) + 1;
10405  Count = 1; // starting value
10406  EntryPos = 1 - Dir;
10407  TempElement = StartElement;
10408  VecPos = StartVecPos;
10409  if(Count == ForwardNumber)
10410  {
10411  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
10412  ForwardSet = true;
10413  }
10414  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
10415  {
10416  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10417  ReverseSet = true;
10418  }
10419  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
10420  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
10421  {
10422  VecPos = TempElement.Conn[1 - EntryPos];
10423  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10424  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
10425  EntryPos = TempEntryPos;
10426  Count++;
10427  if(Count == ForwardNumber)
10428  {
10429  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
10430  ForwardSet = true;
10431  }
10432  if(Count == ReverseNumber)
10433  {
10434  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10435  ReverseSet = true;
10436  }
10437  }
10438  }
10439  }
10440  }
10441  }
10442  }
10443  }
10444  }
10445  for(unsigned int x = 0; x < TrackVector.size(); x++)
10446  {
10447  if(TrackElementAt(1381, x).StationEntryStopLinkPos1 == 5)
10448  {
10450  }
10451  if(TrackElementAt(1383, x).StationEntryStopLinkPos2 == 5)
10452  {
10454  }
10455  }
10456  Utilities->CallLogPop(639);
10457 }
10458 
10459 // ---------------------------------------------------------------------------
10460 
10461 void TTrack::SetNonStationStopLinkEntryPosses(int Caller) //added at v2.18.0
10462 
10463 {
10464 /*at v2.18.0 allow for 2 tracks on a non-station element. Have StationEntryStopLinkPos1 & 2 contain both track entry positions, 0 & 1 in
10465 least sig 2 bits and 2 & 3 in next least sig bits. In use have SESLPos1a == 0 or 1 and SESLPos1b == 2 or 3, and same for Pos2. 'b' values all
10466 set to 0 for platforms, and set appropriately for 2-track non-station locs. SESLPos values are TTrackElement variables only used in program, not
10467 saved in sessions or railways (same as StationEntryStopLinkPos1 & 2).
10468 
10469 Examine each non-station area with same name and, similar to above, look for cases where a track doesn't link to an element with the same name, or
10470 doesn't link at all, this is an end element, check both tracks separately for 4-track elements.
10471 */
10472  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetNonStationStopLinkEntryPosses");
10473  TTrackElement TempElement;
10474  AnsiString TempName;
10475  std::list<unsigned int> NameList; //end elements
10476  std::list<AnsiString> ContinuationNameList; // list of continuation names so can exclude them
10477  for(unsigned int x = 0; x < TrackVector.size(); x++)
10478  {
10479  TrackElementAt(1594, x).StationEntryStopLinkPos3 = -1; // don't clear stopping points 0 & 1 as already set for platforms
10481  if((TrackElementAt(1596, x).TrackType == Continuation) && (TrackElementAt(1641, x).ActiveTrackElementName != ""))
10482  {
10483  ContinuationNameList.push_back(TrackElementAt(1597, x).ActiveTrackElementName);
10484  }
10485  }
10486  ContinuationNameList.sort();
10487  ContinuationNameList.unique();
10488 
10489  for(unsigned int x = 0; x < TrackVector.size(); x++)
10490  {
10491  TempElement = TrackElementAt(1598, x);
10492  if(IsNamedNonStationLocationPresent(3, TempElement.HLoc, TempElement.VLoc))
10493  {
10494  bool NameIsAContinuation = false;
10495  if(std::find(ContinuationNameList.begin(), ContinuationNameList.end(), TempElement.ActiveTrackElementName) != ContinuationNameList.end())
10496  {
10497  NameIsAContinuation = true;
10498  }
10499  if((TempElement.ActiveTrackElementName != "") && !NameIsAContinuation && (TempElement.StationEntryStopLinkPos1 == -1) &&
10500  (TempElement.StationEntryStopLinkPos2 == -1) && (TempElement.StationEntryStopLinkPos3 == -1) && (TempElement.StationEntryStopLinkPos4 == -1))
10501  // Non-station named elements can't be placed on platforms so no conflict with existing stop positions
10502  {
10503  TempName = TempElement.ActiveTrackElementName;
10504  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(1599, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10505  (TrackElementAt(1600, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10506  // an element linked at both ends of single or main track where both links are also named elements with same name
10507  {
10508  if(TempElement.TrackType == Points) //for points links 0 and 2 are the same
10509  {
10510  if(((TempElement.Conn[2] > -1)) && (TempElement.Conn[3] > -1) &&
10511  ((TrackElementAt(1601, TempElement.Conn[2]).ActiveTrackElementName == TempName)) &&
10512  (TrackElementAt(1602, TempElement.Conn[3]).ActiveTrackElementName == TempName))
10513  {
10514  continue; //not an end element so skip it
10515  }
10516  else //reached an end on the diverging leg
10517  {
10518  NameList.push_back(x);
10519  }
10520  }
10521  else if(TempElement.TrackType == Crossover)
10522  {
10523  if((TempElement.Conn[2] > -1) && (TempElement.Conn[3] > -1) &&
10524  (TrackElementAt(1603, TempElement.Conn[2]).ActiveTrackElementName == TempName) &&
10525  (TrackElementAt(1604, TempElement.Conn[3]).ActiveTrackElementName == TempName))
10526  {
10527  continue; //not an end element so skip it
10528  }
10529  else
10530  {
10531  NameList.push_back(x);
10532  }
10533  }
10534  else
10535  {
10536  continue; //not points ot crossover & not an end element so skip
10537  }
10538  }
10539  else // reached one end of single or main track
10540  {
10541  NameList.push_back(x);
10542  }
10543 //NameList now contains all non-station end elements
10544  while(!NameList.empty())
10545  {
10546  unsigned int a = NameList.front();
10547  NameList.pop_front();
10548  TTrackElement &TempElement = TrackElementAt(1605, a);
10549  AnsiString TempName = TempElement.ActiveTrackElementName;
10550  if(TempElement.TrackType == Buffers) //buffer end is 0 so entry must be 1, gaps covered below as any other element
10551  {
10552  TempElement.StationEntryStopLinkPos1 = 1;
10553  }
10554  else
10555  {
10556  if((TempElement.Conn[0] == -1) || (TrackElementAt(1606, TempElement.Conn[0]).ActiveTrackElementName != TempName))
10557  {
10558  TempElement.StationEntryStopLinkPos1 = 1;
10559  }
10560  if((TempElement.Conn[1] == -1) || (TrackElementAt(1607, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10561  {
10562  TempElement.StationEntryStopLinkPos2 = 0;
10563  }
10564  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover))
10565  {
10566  if((TempElement.Conn[2] == -1) || (TrackElementAt(1608, TempElement.Conn[2]).ActiveTrackElementName != TempName))
10567  {
10568  TempElement.StationEntryStopLinkPos3 = 3;
10569  }
10570  if((TempElement.Conn[3] == -1) || (TrackElementAt(1609, TempElement.Conn[3]).ActiveTrackElementName != TempName))
10571  {
10572  TempElement.StationEntryStopLinkPos4 = 2;
10573  }
10574  }
10575  }
10576  }
10577  }
10578  }
10579  }
10580  Utilities->CallLogPop(2640);
10581 }
10582 
10583 // ---------------------------------------------------------------------------
10584 
10585 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10586 {
10587  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10588  TTrackElement Next;
10589 
10591  while(ReturnNextInactiveTrackElement(1, Next))
10592  {
10593  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10594  {
10595  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
10596  // need striped graphics
10597  {
10598  if(Next.SpeedTag == 76)
10599  {
10600  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
10601  }
10602  else if(Next.SpeedTag == 77)
10603  {
10604  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
10605  }
10606  else if(Next.SpeedTag == 78)
10607  {
10608  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
10609  }
10610  else if(Next.SpeedTag == 79)
10611  {
10612  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
10613  }
10614  else if(Next.SpeedTag == 96)
10615  {
10616  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
10617  }
10618  else if(Next.SpeedTag == 131)
10619  {
10620  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
10621  }
10622  }
10623  else
10624  {
10625  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10626  }
10627  }
10628  }
10629 
10630  NextTrackElementPtr = TrackVector.begin();
10631  while(ReturnNextTrackElement(1, Next))
10632  {
10633  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10634  {
10635  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
10636  {
10637  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
10638  {
10639  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
10640  }
10641  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10642  {
10643  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10644  }
10645  }
10646  else
10647  {
10648  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10649  }
10650  }
10651  }
10652  Disp->Update();
10653  Utilities->CallLogPop(640);
10654 }
10655 
10656 // ---------------------------------------------------------------------------
10657 
10658 void TTrack::PlotSmallRedGap(int Caller)
10659 {
10660  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
10662  Utilities->CallLogPop(1346);
10663 }
10664 
10665 // ---------------------------------------------------------------------------
10666 
10667 void TTrack::TrackClear(int Caller)
10668 {
10669  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
10670  TrackVector.clear();
10671  InactiveTrackVector.clear();
10672  TrackMap.clear();
10674  if(TextHandler->TextVector.size() == 0)
10675  {
10676  Display->DisplayOffsetH = 0;
10677  Display->DisplayOffsetV = 0;
10684  HLocMin = 2000000000;
10685  HLocMax = -2000000000;
10686  VLocMin = 2000000000;
10687  VLocMax = -2000000000;
10688  }
10689  else
10690  {
10691  CalcHLocMinEtc(4);
10692  }
10693  Utilities->CallLogPop(1347);
10694 }
10695 
10696 // ---------------------------------------------------------------------------
10697 
10698 void TTrack::CalcHLocMinEtc(int Caller)
10699 {
10700  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
10701  HLocMin = 2000000000;
10702  VLocMin = 2000000000;
10703  HLocMax = -2000000000;
10704  VLocMax = -2000000000;
10705  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
10706  {
10707  if(TrackElementAt(1385, x).SpeedTag == 0)
10708  {
10709  continue; // skip erase elements or would interfere with Min & Max values
10710  }
10711  if(TrackElementAt(1386, x).HLoc - 1 < HLocMin)
10712  {
10713  HLocMin = TrackElementAt(1387, x).HLoc - 1; // add one all round
10714  }
10715  if(TrackElementAt(1388, x).HLoc + 1 > HLocMax)
10716  {
10717  HLocMax = TrackElementAt(1389, x).HLoc + 1;
10718  }
10719  if(TrackElementAt(1390, x).VLoc - 1 < VLocMin)
10720  {
10721  VLocMin = TrackElementAt(1391, x).VLoc - 1;
10722  }
10723  if(TrackElementAt(1392, x).VLoc + 1 > VLocMax)
10724  {
10725  VLocMax = TrackElementAt(1393, x).VLoc + 1;
10726  }
10727  }
10728  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
10729  {
10730  if(InactiveTrackElementAt(150, x).SpeedTag == 0)
10731  {
10732  continue; // shouldn't be any inactive erase elements but include anyway
10733  }
10734  if(InactiveTrackElementAt(151, x).HLoc - 1 < HLocMin)
10735  {
10736  HLocMin = InactiveTrackElementAt(152, x).HLoc - 1; // add one all round
10737  }
10738  if(InactiveTrackElementAt(153, x).HLoc + 1 > HLocMax)
10739  {
10740  HLocMax = InactiveTrackElementAt(162, x).HLoc + 1;
10741  }
10742  if(InactiveTrackElementAt(154, x).VLoc - 1 < VLocMin)
10743  {
10744  VLocMin = InactiveTrackElementAt(155, x).VLoc - 1;
10745  }
10746  if(InactiveTrackElementAt(156, x).VLoc + 1 > VLocMax)
10747  {
10748  VLocMax = InactiveTrackElementAt(157, x).VLoc + 1;
10749  }
10750  }
10751  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
10752  {
10753 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
10754  will fail as x will exceed the maximum value
10755  if(TextHandler->TextPtrAt(, x)->TextString == "")
10756  {
10757  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
10758  }
10759 */
10760  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
10761  if((TextH / 16) - 1 < HLocMin)
10762  {
10763  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
10764  }
10765  if((TextH / 16) + 1 > HLocMax)
10766  {
10767  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
10768  }
10769  if((TextV / 16) - 1 < VLocMin)
10770  {
10771  VLocMin = (TextV / 16) - 1;
10772  }
10773  if((TextV / 16) + 1 > VLocMax)
10774  {
10775  VLocMax = (TextV / 16) + 1;
10776  }
10777  }
10778  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
10779  {
10780  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
10781  {
10782  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
10783  }
10784  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
10785  {
10786  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
10787  }
10788  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
10789  {
10790  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
10791  }
10792  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
10793  {
10794  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
10795  }
10796  }
10797 
10798  Utilities->CallLogPop(641);
10799 }
10800 
10801 // ---------------------------------------------------------------------------
10802 
10803 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
10804  bool &UserGraphicFoundFlag)
10805 {
10806  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
10807  TUserGraphicVector::iterator UserGraphicPtr;
10808 
10809  UserGraphicFoundFlag = false;
10810  if(!UserGraphicVector.empty())
10811  {
10812  int x = UserGraphicVector.size();
10813  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
10814  {
10815  x--;
10816  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
10817  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
10818  {
10819  UserGraphicItem = x;
10820  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
10821  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
10822  UserGraphicFoundFlag = true;
10823  Utilities->CallLogPop(2177);
10824  return;
10825  } // if ....
10826 
10827  } // for UserGraphicPtr...
10828  } // if !UserGraphicVector...
10829 
10830  Utilities->CallLogPop(2197);
10831 }
10832 
10833 // ---------------------------------------------------------------------------
10834 
10836 {
10837  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
10838  TrackElement.LogTrack(11));
10839  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
10840  int SpeedTag = TrackElement.SpeedTag;
10841 
10842  if(SpeedTag < 1)
10843  {
10844  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
10845  }
10846  switch(SpeedTag)
10847  {
10848  case 76: // t platform
10849  GraphicOutput = RailGraphics->gl76Striped;
10850  break;
10851 
10852  case 77: // h platform
10853  GraphicOutput = RailGraphics->bm77Striped;
10854  break;
10855 
10856  case 78: // v platform
10857  GraphicOutput = RailGraphics->bm78Striped;
10858  break;
10859 
10860  case 79: // r platform
10861  GraphicOutput = RailGraphics->gl79Striped;
10862  break;
10863 
10864  case 96: // concourse
10865  GraphicOutput = RailGraphics->ConcourseStriped;
10866  break;
10867 
10868  case 129: // v footbridge
10869  GraphicOutput = RailGraphics->gl129Striped;
10870  break;
10871 
10872  case 130: // h footbridge
10873  GraphicOutput = RailGraphics->gl130Striped;
10874  break;
10875 
10876  case 131: // non-station named loc
10877  GraphicOutput = RailGraphics->bmNameStriped;
10878  break;
10879 
10880  case 145: // v u'pass
10881  GraphicOutput = RailGraphics->gl145Striped;
10882  break;
10883 
10884  case 146: // h u'pass
10885  GraphicOutput = RailGraphics->gl146Striped;
10886  break;
10887 
10888  default:
10889  GraphicOutput = TrackElement.GraphicPtr;
10890  break;
10891  }
10892  Utilities->CallLogPop(642);
10893  return(GraphicOutput);
10894 }
10895 
10896 // ---------------------------------------------------------------------------
10897 
10899 {
10900  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
10901  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10902  {
10903 // Utilities->CallLogPop(2281); this shouldn't be here, introduced 02/06/21 at revision 3745fadb... with no explanation
10904  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
10905  }
10906  Utilities->CallLogPop(643);
10907  return(TrackVector.at(At));
10908 }
10909 
10910 // ---------------------------------------------------------------------------
10911 
10913 {
10914  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
10915  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
10916  {
10917  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
10918  " in InactiveTrackElementAt");
10919  }
10920  Utilities->CallLogPop(644);
10921  return(InactiveTrackVector.at(At));
10922 }
10923 
10924 // ---------------------------------------------------------------------------
10925 
10926 bool TTrack::BlankElementAt(int Caller, int At) const
10927 {
10928  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
10929  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10930  {
10931  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
10932  }
10933  if(TrackVector.at(At).SpeedTag == 0) //have to use TrackVector.at because TrackElementAt is non-const
10934  {
10935  Utilities->CallLogPop(645);
10936  return(true);
10937  }
10938  else
10939  {
10940  Utilities->CallLogPop(646);
10941  return(false);
10942  }
10943 }
10944 
10945 // ---------------------------------------------------------------------------
10946 
10947 bool TTrack::OneStationLongEnoughForSplit(int Caller, AnsiString LocationName)
10948 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
10949  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
10950  split is required a specific check is made using ThisStationLongEnoughForSplit.
10951  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
10952  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
10953 */
10954 {
10955  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneStationLongEnoughForSplit," + LocationName);
10956  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10957  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10958  TLocationNameMultiMapIterator SNIterator;
10959  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10960 
10961  if(SNRange.first == SNRange.second)
10962  {
10963  Utilities->CallLogPop(972);
10964  return(false); // should have been caught earlier but include for completeness
10965  }
10966  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10967  {
10968  if(SNIterator->second < 0)
10969  {
10970  continue; // exclude footcrossings
10971  }
10972  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
10973  if(InactiveElement.TrackType == Concourse)
10974  {
10975  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
10976  }
10977  if(!TrackElementPresentAtHV(1, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
10978  {
10979  continue; // only interested in locations where ActiveTrackElementName may be set
10980  }
10981  THVPair HVPair;
10982  HVPair.first = InactiveElement.HLoc;
10983  HVPair.second = InactiveElement.VLoc;
10984  if(TrackMap.find(HVPair) == TrackMap.end())
10985  {
10986  throw Exception
10987  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneStationLongEnoughForSplit (1)");
10988  }
10989  int TVPos = TrackMap.find(HVPair)->second;
10990  FirstNamedElement = TrackElementAt(560, TVPos);
10991  // first check linked on both sides, skip the check if not
10992  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10993  {
10994  continue;
10995  }
10996  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10997  // ActiveTrackElementNames are points and excluding trailing connections for points
10998  FirstNamedExitPos = 0;
10999  {
11000  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
11001  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
11002  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11003  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
11004  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11005  {
11006  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11007  {
11008  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
11009  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
11010  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
11011  // success, now check FirstNamedElement link not trailing points & if so all OK
11012  {
11013  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
11014  {
11015  Utilities->CallLogPop(1002);
11016  return(true);
11017  }
11018  }
11019  }
11020  }
11021  }
11022  // failed, try link 1
11023  FirstNamedExitPos = 1;
11024  {
11025  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
11026  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
11027  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11028  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
11029  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11030  {
11031  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11032  {
11033  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
11034  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
11035  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
11036  // success, now check FirstNamedElement link not trailing points & if so all OK
11037  {
11038  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
11039  {
11040  Utilities->CallLogPop(1003);
11041  return(true);
11042  }
11043  }
11044  }
11045  }
11046  }
11047  }
11048  Utilities->CallLogPop(1004);
11049  return(false);
11050 }
11051 
11052 // ---------------------------------------------------------------------------
11053 
11054 bool TTrack::OneNonStationLongEnoughForSplit(int Caller, AnsiString LocationName)
11055 /* Check sufficient active elements at same H & V as the non-station element with same ActiveTrackElementName linked together to allow a train split.
11056  Only one train length is needed to return true, but this doesn't mean that all tracks at the location are long enough. When a
11057  split is required a specific check is made using ThisNonStationLongEnoughForSplit.
11058  Need at least two linked ActiveTrackElementNames, with connected elements at each end, or three if one end is a buffer, but no need to check
11059  buffers explicitly as it will come out automatically with the logic applied.
11060  Note that these conditions exclude opposed buffers since these not linked.
11061 */
11062 {
11063  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNonStationLongEnoughForSplit," + LocationName);
11064  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
11065  int FirstNamedExitPos, SecondNamedEntryPos, SecondNamedExitPos;
11066  TLocationNameMultiMapIterator SNIterator;
11067  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11068 
11069  if(SNRange.first == SNRange.second)
11070  {
11071  Utilities->CallLogPop(2641);
11072  return(false); // should have been caught earlier but include for completeness
11073  }
11074  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11075  {
11076  if(SNIterator->second < 0) //negative numbers represent active track elements
11077  {
11078  continue; // exclude footcrossings - only these have active track element names
11079  }
11080  InactiveElement = InactiveTrackElementAt(1412, SNIterator->second);
11081  if(InactiveElement.TrackType == Concourse)
11082  {
11083  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
11084  }
11085  if(!TrackElementPresentAtHV(2, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
11086  {
11087  continue; // only interested in locations where ActiveTrackElementName may be set
11088  }
11089  THVPair HVPair;
11090  HVPair.first = InactiveElement.HLoc;
11091  HVPair.second = InactiveElement.VLoc;
11092  if(TrackMap.find(HVPair) == TrackMap.end())
11093  {
11094  throw Exception ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNonStationLongEnoughForSplit(1)");
11095  }
11096  int TVPos = TrackMap.find(HVPair)->second;
11097  FirstNamedElement = TrackElementAt(1610, TVPos);
11098  // first check linked on both sides, skip the check if not
11099  if(((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1)) && ((FirstNamedElement.Conn[2] == -1) || (FirstNamedElement.Conn[3] == -1)))
11100  {
11101  continue;
11102  }
11103  // check if another ActiveTrackElementName connected via a link
11104  if((FirstNamedElement.Conn[2] == -1) || (FirstNamedElement.Conn[3] == -1)) //examine connections at links 0 & 1
11105  {
11106  FirstNamedExitPos = 0; //this is the end linked to the second named element
11107  {
11108  SecondNamedElement = TrackElementAt(1611, FirstNamedElement.Conn[FirstNamedExitPos]);
11109  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11110  {
11111  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11112  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11113  {
11114  SecondNamedExitPos = 1 - SecondNamedEntryPos; //SecondNamedExitPos is the end not linked to FirstNamedElement
11115  }
11116  else if(SecondNamedEntryPos == 2)
11117  {
11118  SecondNamedExitPos = 3;
11119  }
11120  else if(SecondNamedEntryPos == 3)
11121  {
11122  SecondNamedExitPos = 2;
11123  }
11124  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11125  {
11126  Utilities->CallLogPop(2642);
11127  return(true);
11128  } //if not try other exitpos
11129  }
11130  }
11131  FirstNamedExitPos = 1;
11132  {
11133  SecondNamedElement = TrackElementAt(1612, FirstNamedElement.Conn[FirstNamedExitPos]);
11134  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11135  {
11136  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11137  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11138  {
11139  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11140  }
11141  else if(SecondNamedEntryPos == 2)
11142  {
11143  SecondNamedExitPos = 3;
11144  }
11145  else if(SecondNamedEntryPos == 3)
11146  {
11147  SecondNamedExitPos = 2;
11148  }
11149  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11150  {
11151  Utilities->CallLogPop(2643);
11152  return(true);
11153  } //failed so far, try links 2 & 3, one or other must be linked on both side or would have continued
11154  }
11155  }
11156  }
11157  else if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1)) //examine connections at links 2 & 3
11158  {
11159  FirstNamedExitPos = 2;
11160  {
11161  SecondNamedElement = TrackElementAt(1613, FirstNamedElement.Conn[FirstNamedExitPos]);
11162  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11163  {
11164  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11165  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11166  {
11167  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11168  }
11169  else if(SecondNamedEntryPos == 2)
11170  {
11171  SecondNamedExitPos = 3;
11172  }
11173  else if(SecondNamedEntryPos == 3)
11174  {
11175  SecondNamedExitPos = 2;
11176  }
11177  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11178  {
11179  Utilities->CallLogPop(2644);
11180  return(true);
11181  } //if not try other exitpos
11182  }
11183  }
11184  FirstNamedExitPos = 3;
11185  {
11186  SecondNamedElement = TrackElementAt(1614, FirstNamedElement.Conn[FirstNamedExitPos]);
11187  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11188  {
11189  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11190  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11191  {
11192  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11193  }
11194  else if(SecondNamedEntryPos == 2)
11195  {
11196  SecondNamedExitPos = 3;
11197  }
11198  else if(SecondNamedEntryPos == 3)
11199  {
11200  SecondNamedExitPos = 2;
11201  }
11202  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11203  {
11204  Utilities->CallLogPop(2645);
11205  return(true);
11206  } //failed so continue to next element or return false
11207  }
11208  }
11209  }
11210  }
11211  Utilities->CallLogPop(2646);
11212  return(false);
11213 }
11214 
11215 // ---------------------------------------------------------------------------
11216 
11217 bool TTrack::ThisStationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
11218  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
11219 // for success need two linked named location elements, so that one element of each train can be at the location
11220 // FirstNamedElementPos is the input vector position of the train (lead or mid) and the first (if successful) of the two linked named location elements,
11221 // the second is SecondNamedElementPos of the split train, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
11222 // the two trains will occupy these 4 elements
11223 // All are track vector positions, all but the input being references and set within the function.
11224 {
11225 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links and
11226  including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with connected
11227  elements at each end, or three if one end is a buffer, where the connected elements may or may not be ActiveTrackElementNames, and
11228  no connections via point trailing links. Note that these conditions exclude opposed buffers since these
11229  not linked. Return the split train position in SecondNamedElementPos and exit positions (...LinkedElementPos) for use in train splitting.
11230 */
11231  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisStationLongEnoughForSplit," + LocationName +
11232  AnsiString(FirstNamedElementPos));
11233  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
11234  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
11235 
11236  SecondNamedElementPos = -1;
11237  FirstNamedLinkedElementPos = -1;
11238  SecondNamedLinkedElementPos = -1;
11239  TLocationNameMultiMapIterator SNIterator;
11240  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11241 
11242  if(SNRange.first == SNRange.second) // i.e. location name not in map
11243  {
11244  Utilities->CallLogPop(1005);
11245  return(false); // should have been caught earlier but include for completeness
11246  }
11247  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11248  {
11249  if(SNIterator->second < 0)
11250  {
11251  continue; // exclude footcrossings
11252  }
11253  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
11254  if(InactiveElement.TrackType == Concourse)
11255  {
11256  continue; // only interested in locations where ActiveTrackElementName may be set
11257  }
11258  THVPair HVPair;
11259  HVPair.first = InactiveElement.HLoc;
11260  HVPair.second = InactiveElement.VLoc;
11261  if(TrackMap.find(HVPair) == TrackMap.end())
11262  {
11263  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
11264  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
11265  // then it won't be found in TrackMap but it's still legitimate.
11266  {
11267  continue;
11268  }
11269  else // for anything else throw the error
11270  {
11271  throw Exception
11272  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisStationLongEnoughForSplit (2)");
11273  }
11274  }
11275  int TVPos = TrackMap.find(HVPair)->second;
11276  if(TVPos != FirstNamedElementPos)
11277  {
11278  continue; // looking for an exact match
11279  }
11280  FirstNamedElement = TrackElementAt(567, TVPos);
11281  // first check linked on both sides, skip the check if not
11282  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
11283  {
11284  continue;
11285  }
11286  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
11287  // ActiveTrackElementNames are points and excluding trailing connections for points
11288  FirstNamedExitPos = 0;
11289  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
11290  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
11291  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11292  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
11293  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11294  {
11295  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11296  {
11297  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
11298  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
11299  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
11300  // success, now check FirstNamedElement link not trailing points & if so all OK
11301  {
11302  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
11303  {
11304  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
11305  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
11306  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
11307  Utilities->CallLogPop(1006);
11308  return(true);
11309  }
11310  }
11311  }
11312  }
11313  // failed, try link 1
11314  FirstNamedExitPos = 1;
11315  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
11316  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
11317  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11318  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
11319  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11320  {
11321  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11322  {
11323  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
11324  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
11325  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
11326  // success, now check FirstNamedElement link not trailing points & if so all OK
11327  {
11328  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
11329  {
11330  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
11331  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
11332  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
11333  Utilities->CallLogPop(1007);
11334  return(true);
11335  }
11336  }
11337  }
11338  }
11339  }
11340  Utilities->CallLogPop(1008);
11341  return(false);
11342 }
11343 
11344 // ---------------------------------------------------------------------------
11345 
11346 bool TTrack::ThisNonStationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int TrainLinkPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
11347 // for success need two linked named location elements, so that one element of each train can be at the location
11348 // FirstNamedElementPos is the input vector position of the train (lead or mid) and the first (if successful) of the two linked named location elements,
11349 // the second is SecondNamedElementPos of the split train, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
11350 // the two trains will occupy these 4 elements
11351 // All are track vector positions, all but the input being references and set within the function.
11352 
11353 /* Check sufficient elements with same ActiveTrackElementName linked together and including the element FirstNamedElementPos to allow a train split.
11354  Need at least two linked ActiveTrackElementNames, with connected elements at each end, or three if one end is a buffer, where the connected
11355  elements may or may not be ActiveTrackElementNames. Note that these conditions exclude opposed buffers since these not linked. Return the split
11356  train position in SecondNamedElementPos and exit positions (...LinkedElementPos) for use in train splitting.
11357 */
11358 {
11359  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNonStationLongEnoughForSplit," + LocationName +
11360  AnsiString(FirstNamedElementPos) + "," + AnsiString(TrainLinkPos));
11361  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
11362  int FirstNamedExitPos, SecondNamedEntryPos, SecondNamedExitPos;
11363 
11364  SecondNamedElementPos = -1;
11365  FirstNamedLinkedElementPos = -1;
11366  SecondNamedLinkedElementPos = -1;
11367  TLocationNameMultiMapIterator SNIterator;
11368  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11369 
11370  if(SNRange.first == SNRange.second) // i.e. location name not in map
11371  {
11372  Utilities->CallLogPop(2647);
11373  return(false); // should have been caught earlier but include for completeness
11374  }
11375  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11376  {
11377  if(SNIterator->second < 0) //neg numbers are active track elements
11378  {
11379  continue; // exclude footcrossings
11380  }
11381  InactiveElement = InactiveTrackElementAt(1413, SNIterator->second);
11382  if(InactiveElement.TrackType != NamedNonStationLocation)
11383  {
11384  continue; // only interested in non-station names, shouldn't reach here but inc;ude as a safeguard
11385  }
11386  THVPair HVPair;
11387  HVPair.first = InactiveElement.HLoc;
11388  HVPair.second = InactiveElement.VLoc;
11389  if(TrackMap.find(HVPair) == TrackMap.end()) //no track at this element
11390  {
11391  continue;
11392  }
11393  int TVPos = TrackMap.find(HVPair)->second;
11394  if(TVPos != FirstNamedElementPos)
11395  {
11396  continue; // looking for an exact match
11397  }
11398  FirstNamedElement = TrackElementAt(1615, TVPos);
11399  // first check linked on both sides, skip the check if not
11400  if(((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1)) && ((FirstNamedElement.Conn[2] == -1) || (FirstNamedElement.Conn[3] == -1)))
11401  {
11402  continue;
11403  }
11404  // work on the links that the train is on (e.g. may be on a diagonal so don't want to find valid positions on non-diagonals that train can't reach)
11405  bool LowLinks = true;
11406  if(TrainLinkPos > 1)
11407  {
11408  LowLinks = false;
11409  }
11410  if((LowLinks && FirstNamedElement.Conn[0] > -1) && (FirstNamedElement.Conn[1] > -1)) //examine links 0 & 1
11411  {
11412  FirstNamedExitPos = 0; //this links to the second named element
11413  SecondNamedElement = TrackElementAt(1616, FirstNamedElement.Conn[FirstNamedExitPos]);
11414  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos]; //links to FirstNamedElement
11415  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11416  {
11417  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11418  }
11419  else if(SecondNamedEntryPos == 2)
11420  {
11421  SecondNamedExitPos = 3;
11422  }
11423  else if(SecondNamedEntryPos == 3)
11424  {
11425  SecondNamedExitPos = 2;
11426  }
11427  FirstNamedLinkedElement = TrackElementAt(1617, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11428  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11429  {
11430  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11431  {
11432  SecondNamedLinkedElement = TrackElementAt(1618, SecondNamedElement.Conn[SecondNamedExitPos]);
11433  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
11434  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
11435  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
11436  Utilities->CallLogPop(2648);
11437  return(true);
11438  }
11439  }
11440  // failed, try link 1
11441  FirstNamedExitPos = 1;
11442  SecondNamedElement = TrackElementAt(1619, FirstNamedElement.Conn[FirstNamedExitPos]);
11443  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos]; //links to FirstNamedElement
11444  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11445  {
11446  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11447  }
11448  else if(SecondNamedEntryPos == 2)
11449  {
11450  SecondNamedExitPos = 3;
11451  }
11452  else if(SecondNamedEntryPos == 3)
11453  {
11454  SecondNamedExitPos = 2;
11455  }
11456  FirstNamedLinkedElement = TrackElementAt(1620, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11457  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11458  {
11459  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11460  {
11461  SecondNamedLinkedElement = TrackElementAt(1621, SecondNamedElement.Conn[SecondNamedExitPos]);
11462  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
11463  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
11464  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
11465  Utilities->CallLogPop(2649);
11466  return(true);
11467  }
11468  }
11469  }
11470  else if((!LowLinks && FirstNamedElement.Conn[2] > -1) && (FirstNamedElement.Conn[3] > -1)) //examine links 2 & 3
11471  {
11472  FirstNamedExitPos = 2; //this links to the second named element
11473  SecondNamedElement = TrackElementAt(1622, FirstNamedElement.Conn[FirstNamedExitPos]);
11474  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos]; //links to FirstNamedElement
11475  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11476  {
11477  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11478  }
11479  else if(SecondNamedEntryPos == 2)
11480  {
11481  SecondNamedExitPos = 3;
11482  }
11483  else if(SecondNamedEntryPos == 3)
11484  {
11485  SecondNamedExitPos = 2;
11486  }
11487  FirstNamedLinkedElement = TrackElementAt(1623, FirstNamedElement.Conn[3]);
11488  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11489  {
11490  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11491  {
11492  SecondNamedLinkedElement = TrackElementAt(1624, SecondNamedElement.Conn[SecondNamedExitPos]);
11493  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
11494  FirstNamedLinkedElementPos = FirstNamedElement.Conn[3];
11495  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
11496  Utilities->CallLogPop(2650);
11497  return(true);
11498  }
11499  }
11500  // failed, try link 3
11501  FirstNamedExitPos = 3;
11502  SecondNamedElement = TrackElementAt(1625, FirstNamedElement.Conn[FirstNamedExitPos]);
11503  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos]; //links to FirstNamedElement
11504  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11505  {
11506  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11507  }
11508  else if(SecondNamedEntryPos == 2)
11509  {
11510  SecondNamedExitPos = 3;
11511  }
11512  else if(SecondNamedEntryPos == 3)
11513  {
11514  SecondNamedExitPos = 2;
11515  }
11516  FirstNamedLinkedElement = TrackElementAt(1626, FirstNamedElement.Conn[2]);
11517  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11518  {
11519  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11520  {
11521  SecondNamedLinkedElement = TrackElementAt(1627, SecondNamedElement.Conn[SecondNamedExitPos]);
11522  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
11523  FirstNamedLinkedElementPos = FirstNamedElement.Conn[2];
11524  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
11525  Utilities->CallLogPop(2651);
11526  return(true);
11527  }
11528  }
11529  }
11530  }
11531  Utilities->CallLogPop(2652);
11532  return(false);
11533 }
11534 
11535 // ---------------------------------------------------------------------------
11536 
11537 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
11538 {
11539  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
11540  TLocationNameMultiMapIterator SNIterator;
11541  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11542 
11543  if(SNRange.first != SNRange.second)
11544  {
11545  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11546  {
11547  if(SNIterator->second < 0)
11548  {
11549  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
11550  }
11551  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
11552  SNIterator->second).TrackType == NamedNonStationLocation))
11553  {
11554  Utilities->CallLogPop(1121);
11555  return(true);
11556  }
11557  }
11558  }
11559  Utilities->CallLogPop(848);
11560  return(false);
11561 }
11562 
11563 // ---------------------------------------------------------------------------
11564 
11565 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
11566 {
11567 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
11568  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11569  "," + AnsiString(SpeedTag));
11570  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
11571  {
11572  Utilities->CallLogPop(949);
11573  return(false);
11574  }
11575  bool FoundFlag;
11576  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
11577 
11578  if(!FoundFlag)
11579  {
11580  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
11581  }
11582  TTrackElement IAElement;
11583 
11584  if(SpeedTag == 68) // top sig
11585  {
11586  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
11587  {
11588  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
11589  {
11590  IAElement = InactiveTrackElementAt(50, IMPair.first);
11591  }
11592  else
11593  {
11594  IAElement = InactiveTrackElementAt(51, IMPair.second);
11595  }
11596  if(IAElement.LocationName == "")
11597  {
11598 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
11599  SignalPlatformGraphic = RailGraphics->gl76Striped;
11600  }
11601  else
11602  {
11603 // SignalPlatformGraphic = RailGraphics->Plat68;
11604  SignalPlatformGraphic = RailGraphics->gl76;
11605  }
11606  Utilities->CallLogPop(950);
11607  return(true);
11608  }
11609  }
11610  else if(SpeedTag == 69) // bot sig
11611  {
11612  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
11613  {
11614  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
11615  {
11616  IAElement = InactiveTrackElementAt(77, IMPair.first);
11617  }
11618  else
11619  {
11620  IAElement = InactiveTrackElementAt(78, IMPair.second);
11621  }
11622  if(IAElement.LocationName == "")
11623  {
11624 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
11625  SignalPlatformGraphic = RailGraphics->bm77Striped;
11626  }
11627  else
11628  {
11629 // SignalPlatformGraphic = RailGraphics->Plat69;
11630  SignalPlatformGraphic = RailGraphics->bm77;
11631  }
11632  Utilities->CallLogPop(951);
11633  return(true);
11634  }
11635  }
11636  else if(SpeedTag == 70) // left sig
11637  {
11638  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
11639  {
11640  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
11641  {
11642  IAElement = InactiveTrackElementAt(55, IMPair.first);
11643  }
11644  else
11645  {
11646  IAElement = InactiveTrackElementAt(82, IMPair.second);
11647  }
11648  if(IAElement.LocationName == "")
11649  {
11650 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
11651  SignalPlatformGraphic = RailGraphics->bm78Striped;
11652  }
11653  else
11654  {
11655 // SignalPlatformGraphic = RailGraphics->Plat70;
11656  SignalPlatformGraphic = RailGraphics->bm78;
11657  }
11658  Utilities->CallLogPop(952);
11659  return(true);
11660  }
11661  }
11662  else if(SpeedTag == 71) // right sig
11663  {
11664  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
11665  {
11666  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
11667  {
11668  IAElement = InactiveTrackElementAt(85, IMPair.first);
11669  }
11670  else
11671  {
11672  IAElement = InactiveTrackElementAt(86, IMPair.second);
11673  }
11674  if(IAElement.LocationName == "")
11675  {
11676 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
11677  SignalPlatformGraphic = RailGraphics->gl79Striped;
11678  }
11679  else
11680  {
11681 // SignalPlatformGraphic = RailGraphics->Plat71;
11682  SignalPlatformGraphic = RailGraphics->gl79;
11683  }
11684  Utilities->CallLogPop(953);
11685  return(true);
11686  }
11687  }
11688  Utilities->CallLogPop(954);
11689  return(false);
11690 }
11691 
11692 // ---------------------------------------------------------------------------
11693 
11694 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
11695 // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
11696 // false if not, if NextPos == -1, or if only own train on the track
11697 {
11698  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
11699  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
11700  if(NextEntryPos < 0)
11701  {
11702  Utilities->CallLogPop(1348);
11703  return(false);
11704  }
11705  TTrackElement TrackElement = TrackElementAt(713, NextPos);
11706 
11707  if(TrackElement.TrackType != Bridge)
11708  {
11709  Utilities->CallLogPop(1349);
11710  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
11711  }
11712 // bridge if reach here
11713  if(NextEntryPos > 1)
11714  {
11715  Utilities->CallLogPop(1350);
11716  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 != OwnTrainID));
11717  }
11718  else
11719  {
11720  Utilities->CallLogPop(1351);
11721  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 != OwnTrainID));
11722  }
11723 }
11724 
11725 // ---------------------------------------------------------------------------
11726 
11728 {
11729  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
11730  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
11731  {
11732  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
11733  }
11734  Utilities->CallLogPop(1483);
11735  return(SelectVector.at(At));
11736 }
11737 
11738 // ---------------------------------------------------------------------------
11739 
11740 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
11741 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
11742 {
11743  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
11744  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
11745  bool FoundFlag = false;
11746  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
11747  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
11748 
11749  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
11750  Utilities->CallLogPop(1538);
11751  return(FoundFlag);
11752 }
11753 
11754 // ---------------------------------------------------------------------------
11755 
11756 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
11757 {
11758 // return true if find an inactive element called 'Name'
11759  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
11760  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
11761  bool FoundFlag = false;
11762 
11763  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11764  {
11765  if(InactiveTrackElementAt(158, x).LocationName == Name)
11766  {
11767  FoundFlag = true;
11768  int V = InactiveTrackElementAt(159, x).VLoc;
11769  int H = InactiveTrackElementAt(160, x).HLoc;
11770  if(V > VLocHi)
11771  {
11772  VLocHi = V;
11773  }
11774  if(V < VLocLo)
11775  {
11776  VLocLo = V;
11777  }
11778  if(H < HLoc)
11779  {
11780  HLoc = H;
11781  }
11782  }
11783  }
11784  if(FoundFlag)
11785  {
11786  VPosHi = 16 * VLocHi;
11787  VPosLo = 16 * VLocLo;
11788  HPos = 16 * HLoc;
11789  Utilities->CallLogPop(1562);
11790  return(true);
11791  }
11792  else
11793  {
11794  Utilities->CallLogPop(1563);
11795  return(false);
11796  }
11797 }
11798 
11799 // ---------------------------------------------------------------------------
11800 
11801 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
11802 {
11803 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
11804 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
11805  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
11806  AnsiString(EndTVPosition));
11807  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
11808  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
11809 
11810 // get H & V values for the element adjacent to Link[0] & Link[1]
11811  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
11812  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
11813  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
11814  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
11815 
11816 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
11817  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
11818  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
11819  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
11820  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
11821 
11822  if(Link0Squares <= Link1Squares)
11823  {
11824  Utilities->CallLogPop(1851);
11825  return(0);
11826  }
11827  else
11828  {
11829  Utilities->CallLogPop(1852);
11830  return(1);
11831  }
11832 }
11833 
11834 // ---------------------------------------------------------------------------
11835 
11836 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
11837 {
11838  // element can be points or any other type
11839  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
11840  AnsiString(LinkPos));
11841  Derail = false;
11842  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
11843 
11844  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
11845  {
11846  if(TE.Attribute == 0)
11847  {
11848  Utilities->CallLogPop(663);
11849  return(1); // Att == 0 & ExitPos == 1 represent straight
11850  }
11851  else
11852  {
11853  Utilities->CallLogPop(664);
11854  return(3); // Att == 1 & ExitPos == 3 represent diverging
11855  }
11856  }
11857  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
11858  {
11859  if((LinkPos == 1) && (TE.Attribute == 0))
11860  {
11861  Utilities->CallLogPop(665);
11862  return(0); // Att == 0 represents straight
11863  }
11864  else if(LinkPos == 1)
11865  {
11866  Derail = true;
11867  Utilities->CallLogPop(666);
11868  return(0);
11869  }
11870  else if((LinkPos == 3) && (TE.Attribute == 1))
11871  {
11872  Utilities->CallLogPop(667);
11873  return(0);
11874  }
11875  else if(LinkPos == 3)
11876  {
11877  Derail = true;
11878  Utilities->CallLogPop(668);
11879  return(0);
11880  }
11881  }
11882  else if(LinkPos == 0)
11883  {
11884  Utilities->CallLogPop(669);
11885  return(1);
11886  }
11887  else if(LinkPos == 1)
11888  {
11889  Utilities->CallLogPop(670);
11890  return(0);
11891  }
11892  else if(LinkPos == 2)
11893  {
11894  Utilities->CallLogPop(671);
11895  return(3);
11896  }
11897  else if(LinkPos == 3)
11898  {
11899  Utilities->CallLogPop(672);
11900  return(2);
11901  }
11902  throw Exception("Error, failure in GetExitPos"); // should never reach here
11903 }
11904 
11905 // ----------------------------------------------------------------------------
11906 
11908 {
11909  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
11910  LCVector.clear();
11911  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11912  {
11913  if(InactiveTrackElementAt(161, x).TrackType == LevelCrossing)
11914  {
11915  LCVector.push_back(x);
11916  }
11917  }
11918  Utilities->CallLogPop(1931);
11919  return;
11920 }
11921 
11922 // ---------------------------------------------------------------------------
11923 
11924 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
11925 /*
11926  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
11927  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
11928  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
11929  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
11930 */
11931 {
11932  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
11933  AnsiString(Link));
11934  bool FoundFlag;
11935 
11936  TrainID = -1;
11937  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
11938 
11939  if(!FoundFlag)
11940  {
11941  Utilities->CallLogPop(2001);
11942  return(false);
11943  }
11944  TTrackElement TE = TrackElementAt(882, VecPos);
11945 
11946  TrainID = TE.TrainIDOnElement;
11947  if(TE.TrackType == Bridge)
11948  {
11949  if(TE.TrainIDOnElement > -1)
11950  {
11951  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
11952  {
11954  }
11955  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
11956  {
11958  }
11959  else
11960  {
11961  TrainID = -1; // shouldn't ever reach here but be safe
11962  }
11963  }
11964  }
11965  if(TrainID == -1)
11966  {
11967  Utilities->CallLogPop(2002);
11968  return(false);
11969  }
11970 // now get the train
11971  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
11972 
11973  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
11974  {
11975  Utilities->CallLogPop(2003);
11976  return(true);
11977  }
11978  TrainID = -1;
11979  Utilities->CallLogPop(2004);
11980  return(false);
11981 }
11982 
11983 // ---------------------------------------------------------------------------
11984 
11985 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
11986 /* New at v1.2.0
11987  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
11988  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
11989  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
11990  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
11991  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
11992  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
11993  Each of these is examined in turn for each route element in the relevant position.
11994 */
11995 {
11996  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11997  "," + AnsiString(DiagonalLinkNumber));
11998  TrainID = -1;
11999  TPrefDirElement TempPrefDirElement;
12000  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
12001 
12002  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
12003  {
12004  Utilities->CallLogPop(2027);
12005  return(true);
12006  }
12007  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
12008  {
12009  Utilities->CallLogPop(2028);
12010  return(true);
12011  }
12012  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
12013  {
12014  Utilities->CallLogPop(2029);
12015  return(true);
12016  }
12017  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
12018  {
12019  Utilities->CallLogPop(2030);
12020  return(true);
12021  }
12022  Utilities->CallLogPop(2031);
12023  return(false);
12024 }
12025 
12026 // ---------------------------------------------------------------------------
12027 
12028 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
12029 {
12030  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
12031  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
12032  TUserGraphicItem UGI;
12033  AnsiString JustFileName = "";
12034 
12035  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
12036  {
12037  UGI = UserGraphicVectorAt(17, x);
12038  int LastDelim = UGI.FileName.LastDelimiter('\\');
12039  if(LastDelim == 0) // can't find it so skip this item
12040  {
12041  continue;
12042  }
12043  else
12044  {
12045  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
12046  }
12047  Utilities->SaveFileString(VecFile, JustFileName);
12048  Utilities->SaveFileInt(VecFile, UGI.HPos);
12049  Utilities->SaveFileInt(VecFile, UGI.VPos);
12050  }
12051  Utilities->CallLogPop(2178);
12052 }
12053 
12054 // ---------------------------------------------------------------------------
12055 
12056 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
12057 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
12058 {
12059  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
12060  int NumPlats = 0;
12061  TTrackElement TempElement;
12062  int TempInt;
12063 
12064  typedef std::list<int> TNamePosList;
12065  TNamePosList NamePosList;
12066  typedef TNamePosList::iterator TNPLIt;
12067  TNPLIt NPLIt;
12068  typedef std::list<int> TOnePlatList;
12069  TOnePlatList OnePlatList;
12070  typedef TOnePlatList::iterator TOPLIt;
12071  TOPLIt OPLIt;
12072 
12073  NamePosList.clear();
12074  OnePlatList.clear();
12075  for(unsigned int x = 0; x < TrackVector.size(); x++)
12076  {
12077  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
12078  {
12079  NamePosList.push_back(x);
12080  }
12081  }
12082  //NamePosList complete
12083 
12084  if(!NamePosList.empty()) //first value for the loop examination
12085  {
12086  OnePlatList.push_back(NamePosList.back());
12087  NamePosList.pop_back(); //erase from NPV as done with it here
12088  }
12089  while(!OnePlatList.empty()) //loop to examine all linked elements
12090  {
12091  TempInt = OnePlatList.front();
12092  TempElement = TrackElementAt(989, TempInt);
12093 
12094  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
12095  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
12096  {
12097  OnePlatList.push_back(TempElement.Conn[0]);
12098  NamePosList.erase(NPLIt);
12099  }
12100  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
12101  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
12102  {
12103  OnePlatList.push_back(TempElement.Conn[1]);
12104  NamePosList.erase(NPLIt);
12105  }
12106  //here when loaded any connecting links into OnePlatList, so can erase the front element
12107  OnePlatList.erase(OnePlatList.begin());
12108  if(OnePlatList.empty())
12109  {
12110  NumPlats++; //finished with current linked elements so can increment NumPlats
12111  if(!NamePosList.empty())
12112  {
12113  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
12114  NamePosList.pop_back(); //erase from NPV as done with it there
12115  }
12116  }
12117  }
12118  Utilities->CallLogPop(2218);
12119  return(NumPlats);
12120 }
12121 
12122 // ---------------------------------------------------------------------------
12123 
12124 void TTrack::RepairFailedSignals(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12125 {//repair Signals pointed to by FPVIt
12126  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedSignals," + AnsiString(FPVIt->TVPos));
12127  TTrackElement &TE = Track->TrackElementAt(1516, FPVIt->TVPos);
12128  if(TE.TrackType != SignalPost)
12129  {
12130  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not signal in RepairFailedSignals");
12131  }
12132  if(!TE.Failed)
12133  {
12134  throw Exception("Signals not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedSignals");
12135  }
12136  TE.Failed = false;
12137  //set to correct aspect
12138  int RouteNumber;
12139  if(AllRoutes->GetRouteTypeAndNumber(40, FPVIt->TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
12140  { // 0 for LinkPos ok as a signal so only one track
12141  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(11);
12142  }
12143  //erase from vector
12144  Track->FailedSignalsVector.erase(FPVIt);
12145 
12146  Display->WarningLog(20, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
12147  PerfLogForm->PerformanceLog(43, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
12148  TrainController->StopTTClockMessage(130, "Signal at " + TE.ElementID + " restored to full working order.");
12149  AllRoutes->RebuildRailwayFlag = true;
12150  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot Signals without failed graphic
12151  Utilities->CallLogPop(2519);
12152 }
12153 
12154 // ---------------------------------------------------------------------------
12155 
12156 void TTrack::RepairFailedPoints(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12157 {//repair points pointed to by FPVIt
12158  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedPoints," + AnsiString(FPVIt->TVPos));
12159  TTrackElement &TE = Track->TrackElementAt(1505, FPVIt->TVPos);
12160  if(TE.TrackType != Points)
12161  {
12162  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not points in RepairFailedPoints");
12163  }
12164  if(!TE.Failed)
12165  {
12166  throw Exception("Points not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedPoints");
12167  }
12168  TE.Failed = false;
12173  //erase from vector
12174  Track->FailedPointsVector.erase(FPVIt);
12175 
12176  Display->WarningLog(15, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
12177  PerfLogForm->PerformanceLog(38, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
12178  TrainController->StopTTClockMessage(123, "Points at " + TE.ElementID + " restored to full working order.");
12179  AllRoutes->RebuildRailwayFlag = true;
12180  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
12181  Utilities->CallLogPop(2518);
12182 }
12183 
12184 // ---------------------------------------------------------------------------
12185 
12186 void TTrack::RepairTSR(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12187 {//repair TSR pointed to by FPVIt
12188  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairTSR," + AnsiString(FPVIt->TVPos));
12189  TTrackElement &TE = Track->TrackElementAt(1535, FPVIt->TVPos);
12190  if(TE.TrackType != Simple)
12191  {
12192  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not simple in RepairFailedPoints");
12193  }
12194  if(!TE.Failed)
12195  {
12196  throw Exception("No TSR at " + AnsiString(FPVIt->TVPos) + " in RepairTSR");
12197  }
12198  TE.Failed = false;
12201  //erase from vector
12202  Track->TSRVector.erase(FPVIt);
12203 
12204  Display->WarningLog(21, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
12205  PerfLogForm->PerformanceLog(44, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
12206  TrainController->StopTTClockMessage(131, "Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order.");
12207  AllRoutes->RebuildRailwayFlag = true;
12208  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
12209  Utilities->CallLogPop(2520);
12210 }
12211 
12212 // ---------------------------------------------------------------------------
12213 
12215 {
12216  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PopulateSimpleVector");
12217  SimpleVector.clear();
12218  for(unsigned int x = 0; x < TrackVector.size(); x++)
12219  {
12220  if(TrackElementAt(1517, x).TrackType == Simple)
12221  {
12222  SimpleVector.push_back(int(x));
12223  }
12224  }
12225  Utilities->CallLogPop(2521);
12226 }
12227 
12228 // ---------------------------------------------------------------------------
12229 // UserGraphic, PrefDir & Route functions
12230 // ---------------------------------------------------------------------------
12231 
12233 {
12234  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
12235  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
12236  {
12237  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
12238  }
12239  Utilities->CallLogPop(2194);
12240  return(UserGraphicVector.at(At));
12241 }
12242 
12243 // ---------------------------------------------------------------------------
12244 
12245 int TOnePrefDir::LastElementNumber(int Caller) const
12246 {
12247  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
12248  int RetVal = PrefDirVector.size() - 1;
12249 
12250  if(RetVal < 0)
12251  {
12252  throw Exception("Return value negative in call to LastElementNumber");
12253  }
12254  Utilities->CallLogPop(114);
12255  return(RetVal);
12256 }
12257 
12258 // ---------------------------------------------------------------------------
12260 {
12261  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
12262  if(PrefDirVector.empty())
12263  {
12264  throw Exception("PrefDirVector empty in call to LastElementPtr");
12265  }
12266  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
12267 
12268  Utilities->CallLogPop(115);
12269  return(RetIT);
12270 }
12271 
12272 // ---------------------------------------------------------------------------
12274 {
12275  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
12276  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
12277  {
12278  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
12279  }
12280  Utilities->CallLogPop(116);
12281  return(PrefDirVector.at(At));
12282 }
12283 
12284 // ---------------------------------------------------------------------------
12286 {
12287  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
12288  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
12289  {
12290  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
12291  " in GetModifiablePrefDirElementAt");
12292  }
12293  Utilities->CallLogPop(117);
12294  return(PrefDirVector.at(At));
12295 }
12296 
12297 // ---------------------------------------------------------------------------
12299 {
12300  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
12301  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
12302  {
12303  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
12304  }
12305  Utilities->CallLogPop(118);
12306  return(SearchVector.at(At));
12307 }
12308 
12309 // ---------------------------------------------------------------------------
12311 {
12312  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
12313  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
12314  {
12315  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
12316  }
12317  Utilities->CallLogPop(119);
12318  return(SearchVector.at(At));
12319 }
12320 
12321 // ---------------------------------------------------------------------------
12322 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
12323 /*
12324  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
12325  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
12326  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
12327  set in later functions.
12328 */
12329 {
12330  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12331  ClearPrefDir();
12332  int TrackVectorPosition;
12333  TTrackElement TrackElement;
12334 
12335  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12336  {
12337  Utilities->CallLogPop(126);
12338  return(false);
12339  }
12340 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
12341  if(TrackElement.TrackType == Points)
12342  {
12343  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
12344  //it isn't known which trailing edge is the required PrefDir - could use the straight as
12345  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
12346  //best to prevent it to avoid problems
12347  Utilities->CallLogPop(127);
12348  return false;
12349  }
12350 */
12351  TPrefDirElement PrefDirElement(TrackElement);
12352 
12353  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
12354  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
12355  StorePrefDirElement(1, PrefDirElement); // enter first element
12356 // Note that ELink not set even if a buffer or continuation - these set in
12357 // ConvertPrefDirSearchVector after 2nd element added
12358 
12359  Utilities->CallLogPop(128);
12360  return(true);
12361 }
12362 
12363 // ---------------------------------------------------------------------------
12364 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
12365 
12366 /*
12367  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
12368  Examine the last element in the PrefDirVector, if ELink not set (start element) do an immediate
12369  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
12370  with setting the PrefDir vector, & return true.
12371  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
12372  SearchForPrefDir to examine all branches. If succeed set PrefDirVector.
12373  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
12374  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
12375  ConvertPrefDirSearchVector to set PrefDirVector.
12376  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
12377  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
12378  find the required element return false. CheckCount is used to keep track of set values to allow check later.
12379 */
12380 
12381 {
12382  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12383  FinishElement = false;
12384  int TrackVectorPosition;
12385 
12386  TotalSearchCount = 0;
12387  TTrackElement TrackElement, TempTrackElement;
12388 
12389  if(PrefDirVector.size() == 0)
12390  {
12391  Utilities->CallLogPop(129);
12392  return(false);
12393  }
12394  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12395  {
12396  Utilities->CallLogPop(130);
12397  return(false);
12398  }
12399 // set the search limits using the last stored element in PrefDirVector as the start point
12400 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
12401 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
12402 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
12403 
12404  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
12405 
12406  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
12407  {
12408  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
12409  SearchLimitHighH = TrackElement.HLoc + 15;
12410  }
12411  else
12412  {
12413  SearchLimitLowH = TrackElement.HLoc - 15;
12414  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
12415  }
12416  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
12417  {
12418  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
12419  SearchLimitHighV = TrackElement.VLoc + 15;
12420  }
12421  else
12422  {
12423  SearchLimitLowV = TrackElement.VLoc - 15;
12424  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
12425  }
12426 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
12427  check & TotalSearchCounts check
12428  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
12429  {
12430  ShowMessage("Unable to reach the selected element - too far ahead");
12431  Utilities->CallLogPop(1692);
12432  return false;
12433  }
12434 */
12435 // get last PrefDir element
12436  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
12437  {
12438  // check if TrackElement adjacent to any of the 4 XLinkPos'
12439  for(int x = 0; x < 4; x++)
12440  {
12441  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
12442  {
12443  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
12444  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
12445  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
12446  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
12447  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
12448  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
12449  // shouldn't ever get it in a serious railway though.
12450 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
12451  }
12452  }
12453  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
12454  {
12455  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
12456  SearchVector.clear(); // use this & convert to set all PrefDir element values
12457  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
12458  {
12460  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12461  {
12462  FinishElement = true;
12463  }
12464  Utilities->CallLogPop(131);
12465  return(true);
12466  }
12467  } // not an adjacent element
12468 
12469  // now check each of the 4 possible XLinkPos values
12470  for(int x = 0; x < 4; x++)
12471  {
12472  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
12473  {
12474  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
12475  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
12476  SearchVector.clear();
12477  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
12478  {
12480  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12481  {
12482  FinishElement = true;
12483  }
12484  Utilities->CallLogPop(132);
12485  return(true);
12486  }
12487  }
12488  } // here if checked all possible exits without success
12489  ShowMessage(
12490  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12491  Utilities->CallLogPop(133);
12492  return(false);
12493  }
12494 // dealt above with LastPrefDirElement being the start element (which can be points)
12495 
12496  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
12497  .ELinkPos] == Lead)) // leading point
12498  {
12499  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
12500  {
12501  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
12502  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
12503  // can't be buffers or gap if points
12504  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
12505  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
12506  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
12507  SearchVector.clear();
12508  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
12509  {
12511  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12512  {
12513  FinishElement = true;
12514  }
12515  Utilities->CallLogPop(134);
12516  return(true);
12517  }
12518  }
12519  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
12520  {
12521  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
12522  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
12523  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
12524  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
12525  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
12526  SearchVector.clear();
12527  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
12528  {
12530  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12531  {
12532  FinishElement = true;
12533  }
12534  Utilities->CallLogPop(135);
12535  return(true);
12536  }
12537  }
12538 // above dealt with immediate finds for leading point,
12539 // now deal with ordinary searches for leading point
12540  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
12541  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
12542  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
12543  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
12544  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
12545  SearchVector.clear();
12546  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
12547  {
12549  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12550  {
12551  FinishElement = true;
12552  }
12553  Utilities->CallLogPop(136);
12554  return(true);
12555  }
12556  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
12557  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
12558  // note that CheckCount already increased to allow for XLinkPos & XLink
12559  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
12560  SearchVector.clear();
12561  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
12562  {
12564  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12565  {
12566  FinishElement = true;
12567  }
12568  Utilities->CallLogPop(137);
12569  return(true);
12570  }
12571 // here if failed to find match for leading point
12572  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
12573  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
12574  ShowMessage(
12575  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12576  Utilities->CallLogPop(138);
12577  return(false);
12578  }
12579 // leading point fully dealt with above
12580 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
12581 // separately as covered in ordinary search.
12582 
12583  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
12584  SearchVector.clear();
12585 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
12586  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
12587  {
12589  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12590  {
12591  FinishElement = true;
12592  }
12593  Utilities->CallLogPop(139);
12594  return(true);
12595  }
12596  ShowMessage(
12597  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12598  Utilities->CallLogPop(140);
12599  return(false); // failed to find required element
12600 }
12601 
12602 // ---------------------------------------------------------------------------
12603 
12604 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
12605 /*
12606  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
12607  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
12608  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
12609  Keep a count of entries in SearchVector during the current function call, so that this number can be
12610  erased for an unproductive branch search.
12611  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
12612  element. If so save it & return true. If not check if buffer, continuation, or earlier position
12613  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
12614  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
12615  If not any of above, store element in searchvector, set the new current element values from the
12616  SearchElement, then go back to the while loop for the next step in the search.
12617 */
12618 {
12619  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
12620  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
12621  int VectorCount = 0;
12622 
12623  while(true)
12624  {
12625  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
12626  {
12627  for(int x = 0; x < VectorCount; x++)
12628  {
12629  SearchVector.erase(SearchVector.end() - 1);
12630  }
12631  Utilities->CallLogPop(141);
12632  return(false);
12633  }
12634  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
12635  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
12636  TPrefDirElement SearchElement(NextTrackElement);
12637  SearchElement.TrackVectorPosition = NextPosition;
12638  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
12639  SearchElement.ELinkPos = NextELinkPos;
12640  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
12641  int NextXLinkPos;
12642  if(SearchElement.ELinkPos == 0)
12643  {
12644  NextXLinkPos = 1;
12645  }
12646  if(SearchElement.ELinkPos == 1)
12647  {
12648  NextXLinkPos = 0;
12649  }
12650  if(SearchElement.ELinkPos == 2)
12651  {
12652  NextXLinkPos = 3;
12653  }
12654  if(SearchElement.ELinkPos == 3)
12655  {
12656  NextXLinkPos = 2;
12657  }
12658  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
12659  {
12660  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
12661  // but may be buffers, continuation or gap
12662  SearchElement.XLinkPos = NextXLinkPos;
12663  }
12664 // can't set XLink or XLinkPos yet if the element is a leading point.
12665 // check if found it
12666  if(SearchElement.TrackVectorPosition == RequiredPosition)
12667  {
12668  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
12669  VectorCount++; // not really needed but include for tidyness
12670  TotalSearchCount++;
12671  Utilities->CallLogPop(142);
12672  return(true);
12673  }
12674 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
12675 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
12676 // at a time - drop this
12677 /*
12678  if(PrefDirVector.size() > 200)
12679  {
12680  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
12681  Utilities->CallLogPop(1419);
12682  return false;
12683  }
12684 */
12685 // check if a buffer or continuation
12686  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
12687  {
12688  for(int x = 0; x < VectorCount; x++)
12689  {
12690  SearchVector.erase(SearchVector.end() - 1);
12691  }
12692  Utilities->CallLogPop(143);
12693  return(false);
12694  }
12695 // check if reached an earlier position on search PrefDir with same entry value
12696  for(unsigned int x = 0; x < SearchVector.size(); x++)
12697  {
12698  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
12699  {
12700  for(int x = 0; x < VectorCount; x++)
12701  {
12702  SearchVector.erase(SearchVector.end() - 1);
12703  }
12704  Utilities->CallLogPop(144);
12705  return(false);
12706  }
12707  }
12708 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
12709 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
12710  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12711  {
12712  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
12713  {
12714  for(int x = 0; x < VectorCount; x++)
12715  {
12716  SearchVector.erase(SearchVector.end() - 1);
12717  }
12718  Utilities->CallLogPop(1417);
12719  return(false);
12720  }
12721  }
12722 
12723 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
12724 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
12725 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
12727  {
12728  for(int x = 0; x < VectorCount; x++)
12729  {
12730  SearchVector.erase(SearchVector.end() - 1);
12731  }
12732  Utilities->CallLogPop(1691);
12733  return(false);
12734  }
12735 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
12736  if(SearchVector.size() > 150)
12737  {
12738  for(int x = 0; x < VectorCount; x++)
12739  {
12740  SearchVector.erase(SearchVector.end() - 1);
12741  }
12742  Utilities->CallLogPop(1418);
12743  return(false);
12744  }
12745 // check if reached a leading point
12746  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
12747  {
12748 // push element with XLink set to position [1]
12749  SearchElement.XLink = SearchElement.Link[1];
12750  SearchElement.XLinkPos = 1;
12751  SearchVector.push_back(SearchElement);
12752  VectorCount++;
12753  TotalSearchCount++;
12754  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
12755  // Note that have to use a TTrackElement in the recursive search, so SearchElement
12756  // can't be used. NextTrackElement is the corresponding TTrackElement.
12757  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
12758  {
12759  Utilities->CallLogPop(145);
12760  return(true);
12761  }
12762  else
12763  {
12764 // remove leading point with XLinkPos [1]
12765  SearchVector.erase(SearchVector.end() - 1);
12766  VectorCount--;
12767 // push element with XLink set to position [3]
12768  SearchElement.XLink = SearchElement.Link[3];
12769  SearchElement.XLinkPos = 3;
12770  SearchVector.push_back(SearchElement);
12771  VectorCount++;
12772  TotalSearchCount++;
12773 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
12774  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
12775  {
12776  Utilities->CallLogPop(146);
12777  return(true);
12778  }
12779  else
12780  {
12781  for(int x = 0; x < VectorCount; x++)
12782  {
12783  SearchVector.erase(SearchVector.end() - 1);
12784  }
12785  Utilities->CallLogPop(147);
12786  return(false);
12787  }
12788  }
12789  } // if leading point
12790 
12791 // here if ordinary element, push it, inc vector & update CurrentTrackElement
12792 // ready for next element on PrefDir
12793  SearchVector.push_back(SearchElement);
12794  VectorCount++;
12795  TotalSearchCount++;
12796  XLinkPos = NextXLinkPos;
12797  CurrentTrackElement = SearchElement;
12798  } // while(true)
12799 }
12800 
12801 // ---------------------------------------------------------------------------
12802 
12804 /*
12805  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
12806  for each element on the search PrefDir, though if the last element is a leading point
12807  then the final XLink won't be set.
12808  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
12809  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
12810  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
12811 */
12812 {
12813  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
12814  if(SearchVector.size() == 0)
12815  {
12816  throw Exception("Error, SearchVector empty");
12817  }
12818 // get first SearchElement in order to set last PrefDirelement
12819  TPrefDirElement SearchElement = SearchVector.at(0);
12820 
12821 // set last PrefDir element XLink & ELink values if not already set
12822 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
12823  for(int x = 0; x < 4; x++)
12824  {
12825  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
12826  {
12827  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
12828  {
12829  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
12830  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
12831  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
12832  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
12833  }
12834  int ELinkPos;
12835  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
12836  {
12837  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
12838  }
12839  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
12840  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
12841  {
12842  ELinkPos = 0;
12843  }
12844  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
12845  {
12846  ELinkPos = 3;
12847  }
12848  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
12849  {
12850  ELinkPos = 2;
12851  }
12852  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
12853  {
12854  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
12855  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
12856  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
12857  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
12858  }
12859  break; // no point going any further
12860  }
12861  }
12862 // set EXNumber for last PrefDir element, unless already set
12863 // won't be set if was first element or a leading point
12864  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
12865  {
12866 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
12867  int EXArray[32][2] = {
12868  {4,6},{2,8}, //horizontal & vertical
12869  {2,4},{6,2},{8,6},{4,8}, //sharp curves
12870  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
12871  {1,9},{3,7} //forward & reverse diagonals
12872 */
12873 
12874  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
12875  {
12876  throw Exception("Error in EntryExitNumber 1");
12877  }
12878  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
12879  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
12880  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
12881  }
12882 // Last PrefDir element now complete
12883 
12884 // construct remaining PrefDir elements from searchvector
12885  for(unsigned int x = 0; x < SearchVector.size(); x++)
12886  {
12887  SearchElement = SearchVector.at(x);
12888  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
12889  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
12890  PrefDirElement.ELink = SearchElement.ELink;
12891  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
12892  PrefDirElement.XLink = SearchElement.XLink;
12893  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
12894 // if XLink & XLinkPos not set don't account for them in CheckCount
12895  if(PrefDirElement.XLink == -1)
12896  {
12897  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12898  }
12899  // & TrackVectorPosition
12900  else
12901  {
12902  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12903  }
12904  // XLink, XLinkPos, TrackVectorPosition
12905 
12906 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
12907  if(PrefDirElement.XLink != -1)
12908  {
12909  if(!(PrefDirElement.EntryExitNumber()))
12910  {
12911  throw Exception("Error in EntryExitNumber 2");
12912  }
12913  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
12914  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
12915  PrefDirElement.CheckCount++;
12916  // all values now incorporated if not a leading point
12917  }
12918 // store PrefDir element
12919  StorePrefDirElement(2, PrefDirElement);
12920  }
12921 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
12922  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
12923  {
12924  if(ValidatePrefDir(2))
12925  {
12926  ;
12927  } // error messages given within function
12928 
12929  }
12931 /* drop this, check dropped from search
12932  if(PrefDirVector.size() > 200)
12933  {
12934  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
12935  }
12936 */
12937  Utilities->CallLogPop(148);
12938 }
12939 
12940 // ---------------------------------------------------------------------------
12941 
12942 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
12943 /*
12944  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
12945  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
12946 */
12947 {
12948  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
12949  LeadingPoints = false;
12950  if(PrefDirVector.empty())
12951  {
12952  Utilities->CallLogPop(1786);
12953  return(false); // should never be empty but allow for it for safety
12954  }
12955  if(PrefDirVector.size() == 1)
12956  {
12957  Utilities->CallLogPop(149);
12958  return(false); // can't end if only one element
12959  }
12960 /*
12961  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
12962  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
12963  {
12964  Utilities->CallLogPop(150);
12965  return true;
12966  }
12967 */
12968 // allow for anything but leading points
12969  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
12970  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
12971  {
12972  Utilities->CallLogPop(1776);
12973  return(true);
12974  }
12975  else
12976  {
12977  LeadingPoints = true;
12978  Utilities->CallLogPop(151);
12979  return(false);
12980  }
12981 }
12982 
12983 // ---------------------------------------------------------------------------
12984 
12986 /*
12987  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
12988  and that every element is connected to the next element
12989 */
12990 {
12991  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
12992  int Position;
12993  AnsiString ErrorString;
12994  bool Error = false;
12995 
12996  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12997  {
12998  if(PrefDirVector.at(x).HLoc == -2000000000)
12999  {
13000  Error = true;
13001  ErrorString = "HLoc";
13002  Position = x;
13003  }
13004  if(PrefDirVector.at(x).VLoc == -2000000000)
13005  {
13006  Error = true;
13007  ErrorString = "VLoc";
13008  Position = x;
13009  }
13010  if(PrefDirVector.at(x).ELink == -1)
13011  {
13012  Error = true;
13013  ErrorString = "ELink";
13014  Position = x;
13015  }
13016  if(PrefDirVector.at(x).ELinkPos == -1)
13017  {
13018  Error = true;
13019  ErrorString = "ELinkPos";
13020  Position = x;
13021  }
13022  if(PrefDirVector.at(x).XLink == -1)
13023  {
13024  Error = true;
13025  ErrorString = "XLink";
13026  Position = x;
13027  }
13028  if(PrefDirVector.at(x).XLinkPos == -1)
13029  {
13030  Error = true;
13031  ErrorString = "XLinkPos";
13032  Position = x;
13033  }
13034  if(PrefDirVector.at(x).SpeedTag == 0)
13035  {
13036  Error = true;
13037  ErrorString = "Tag";
13038  Position = x;
13039  }
13040  if(PrefDirVector.at(x).TrackVectorPosition == -1)
13041  {
13042  Error = true;
13043  ErrorString = "TrackVectorPosition";
13044  Position = x;
13045  }
13046  if(PrefDirVector.at(x).EXNumber == -1)
13047  {
13048  Error = true;
13049  ErrorString = "EXNumber";
13050  Position = x;
13051  }
13052  if(PrefDirVector.at(x).CheckCount != 9)
13053  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
13054  {
13055  Error = true;
13056  ErrorString = "CheckCount";
13057  Position = x;
13058  }
13059 // extra checks
13060  if(PrefDirVector.at(x).EXGraphicPtr == 0)
13061  {
13062  Error = true;
13063  ErrorString = "EntryGraphicPtr";
13064  Position = x;
13065  }
13066  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
13067  {
13068  Error = true;
13069  ErrorString = "EntryDirectionGraphicPtr";
13070  Position = x;
13071  }
13072 // end of extra checks
13073  if(x > 0)
13074  {
13075  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
13076  {
13077  Error = true;
13078  ErrorString = "Last XLink not connected to this element";
13079  Position = x;
13080  }
13081  }
13082  }
13083  if(Error)
13084  {
13085  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
13086  }
13087  else
13088  {
13089  Utilities->CallLogPop(153);
13090  return(true);
13091  }
13092 }
13093 
13094 // ---------------------------------------------------------------------------
13095 
13096 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
13097 /*
13098  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
13099  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
13100  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
13101  or a leading point.
13102 */
13103 {
13104  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13105  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
13106  {
13107  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
13108  {
13109  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
13110  {
13111  ErasePrefDirElementAt(1, PrefDirVecPos);
13112  }
13113  if(PrefDirVector.size() == 0)
13114  {
13115  Utilities->CallLogPop(154);
13116  return(true);
13117  }
13118  if(PrefDirVector.size() == 1)
13119  {
13120  PrefDirVector.at(x - 1).ELinkPos = -1;
13121  PrefDirVector.at(x - 1).ELink = -1;
13122  PrefDirVector.at(x - 1).XLinkPos = -1;
13123  PrefDirVector.at(x - 1).XLink = -1;
13124  PrefDirVector.at(x - 1).EXNumber = -1;
13125  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
13126  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
13127  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
13128  Utilities->CallLogPop(155);
13129  return(true);
13130  }
13131  // here with truncate element not first element, so ELink & ELinkPos set
13132  // unset XLink & Pos if a leading point
13133  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
13134  {
13135  PrefDirVector.at(x - 1).XLinkPos = -1;
13136  PrefDirVector.at(x - 1).XLink = -1;
13137  PrefDirVector.at(x - 1).EXNumber = -1;
13138  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
13139  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
13140  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
13141  Utilities->CallLogPop(156);
13142  return(true);
13143  }
13144  Utilities->CallLogPop(157);
13145  return(true);
13146  }
13147  }
13148  Utilities->CallLogPop(158);
13149  return(false);
13150 }
13151 
13152 // ---------------------------------------------------------------------------
13153 
13154 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
13155 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
13156 /*
13157  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
13158  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
13159  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
13160  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
13161  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
13162  displayed.
13163 */
13164 {
13165  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
13166  AnsiString((short)BuildingPrefDir));
13167  int HPos, VPos;
13168 
13169  if(PrefDirSize() == 0)
13170  {
13171  Utilities->CallLogPop(159);
13172  return;
13173  }
13174  for(unsigned int x = 0; x < PrefDirSize(); x++)
13175  {
13176  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
13177 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
13178 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
13179 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
13180  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
13181  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
13182  // only the front half of which will be overplotted by the back of the train, then when the train is
13183  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
13184  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
13185  {
13186  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
13187  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
13188  {
13189  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13190  }
13191  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
13192  // Route, no direction if a single element
13193  {
13194  if(x == 0)
13195  {
13196  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13197  }
13198  if(x == (PrefDirSize() - 1))
13199  {
13200  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13201  }
13202  }
13203  }
13204  }
13205 
13206 // set start & end element colours if building a PrefDir
13207  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
13208  {
13209  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
13210  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
13211  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
13212  // set last element colour
13213  if(PrefDirSize() > 1)
13214  {
13215  unsigned int LatestPos = PrefDirSize() - 1;
13216  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
13217  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
13218  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
13219  }
13220  }
13221  Disp->Update();
13222  Utilities->CallLogPop(160);
13223 }
13224 
13225 // ---------------------------------------------------------------------------
13226 
13228 /*
13229  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
13230  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
13231 */
13232 {
13233  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
13234  if(PrefDirSize() == 0)
13235  {
13236  Utilities->CallLogPop(1547);
13237  return;
13238  }
13239  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13240  bool FoundFlag;
13242  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13243 
13244  while(MMIT != PrefDir4MultiMap.end())
13245  {
13246  H = MMIT->first.first;
13247  V = MMIT->first.second;
13248  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13249  // always found in order, any missing have PrefDirPosx == -1
13250  if(PrefDirPos0 > -1)
13251  {
13252  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13253  }
13254  if(PrefDirPos1 > -1)
13255  {
13256  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
13257  }
13258  if(PrefDirPos2 > -1)
13259  {
13260  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
13261  }
13262  if(PrefDirPos3 > -1)
13263  {
13264  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
13265  }
13266  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
13267  {
13268  // need to plot all 4 in order to obtain all the direction graphics
13269  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13270  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13271  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13272  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13273  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13274  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13275  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
13276  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
13277  MMIT++;
13278  MMIT++;
13279  MMIT++;
13280  MMIT++;
13281  }
13282  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13283  {
13284  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13285  {
13286  // 0 & 1 constitute the bidirectional PrefDir
13287  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
13288  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
13289  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13290  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13291  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13292  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13293  MMIT++;
13294  MMIT++;
13295  MMIT++;
13296  }
13297  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
13298  {
13299  // 0 & 2 constitute the bidirectional PrefDir
13300  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13301  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13302  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13303  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13304  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13305  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13306  MMIT++;
13307  MMIT++;
13308  MMIT++;
13309  }
13310  else
13311  {
13312  // 1 & 2 constitute the bidirectional PrefDir
13313  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13314  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13315  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13316  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13317  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13318  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13319  MMIT++;
13320  MMIT++;
13321  MMIT++;
13322  }
13323  }
13324  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13325  {
13326  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13327  {
13328  // 0 & 1 constitute the bidirectional PrefDir
13329  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13330  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13331  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13332  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13333  MMIT++;
13334  MMIT++;
13335  }
13336  else
13337  {
13338  // 2 unidirectional PrefDirs
13339  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13340  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13341  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13342  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13343  MMIT++;
13344  MMIT++;
13345  }
13346  }
13347  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
13348  {
13349  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13350  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13351  MMIT++;
13352  }
13353  }
13354  Disp->Update();
13355  Utilities->CallLogPop(1548);
13356 }
13357 
13358 // ---------------------------------------------------------------------------
13359 
13360 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
13361 {
13362  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
13363  int TempInt;
13364 
13365  ClearPrefDir();
13366  int NumberOfPrefDirElements = 0;
13367 
13368  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13369  for(int x = 0; x < NumberOfPrefDirElements; x++)
13370  {
13371  VecFile >> TempInt; // TrackVectorPosition
13372  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
13373  LoadPrefDirElement.TrackVectorPosition = TempInt;
13374  VecFile >> TempInt;
13375  LoadPrefDirElement.ELink = TempInt;
13376  VecFile >> TempInt;
13377  LoadPrefDirElement.ELinkPos = TempInt;
13378  VecFile >> TempInt;
13379  LoadPrefDirElement.XLink = TempInt;
13380  VecFile >> TempInt;
13381  LoadPrefDirElement.XLinkPos = TempInt;
13382  VecFile >> TempInt;
13383  LoadPrefDirElement.EXNumber = TempInt;
13384  VecFile >> TempInt;
13385  LoadPrefDirElement.CheckCount = TempInt;
13386  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
13387  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
13388  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
13389  if(!(LoadPrefDirElement.IsARoute))
13390  {
13391  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
13392  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
13393  }
13394  else
13395  {
13396  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
13397  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
13398  LoadPrefDirElement.PrefDirRoute);
13399  }
13400  StorePrefDirElement(5, LoadPrefDirElement);
13401  Utilities->LoadFileString(VecFile); // marker
13402  }
13404  Utilities->CallLogPop(161);
13405 }
13406 
13407 // ---------------------------------------------------------------------------
13408 
13409 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
13410 {
13411  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
13412  int TempInt;
13413 
13414  ClearPrefDir();
13415  int NumberOfPrefDirElements = 0;
13416 
13417  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13418  for(int x = 0; x < NumberOfPrefDirElements; x++)
13419  {
13420  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
13421  VecFile >> TempInt; // TrackVectorPosition
13422  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt)); //Loads all basic TrackElement values incl HLoc, VLoc & SpeedTag
13423  LoadPrefDirElement.TrackVectorPosition = TempInt;
13424  VecFile >> TempInt;
13425  LoadPrefDirElement.ELink = TempInt;
13426  VecFile >> TempInt;
13427  LoadPrefDirElement.ELinkPos = TempInt;
13428  VecFile >> TempInt;
13429  LoadPrefDirElement.XLink = TempInt;
13430  VecFile >> TempInt;
13431  LoadPrefDirElement.XLinkPos = TempInt;
13432  VecFile >> TempInt;
13433  LoadPrefDirElement.EXNumber = TempInt;
13434  VecFile >> TempInt;
13435  LoadPrefDirElement.CheckCount = TempInt;
13436  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
13437  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
13438  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
13439  if(!(LoadPrefDirElement.IsARoute))
13440  {
13441  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
13442  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
13443  }
13444  else
13445  {
13446  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
13447  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
13448  LoadPrefDirElement.PrefDirRoute);
13449  }
13450  StorePrefDirElement(0, LoadPrefDirElement);
13451  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
13452  }
13454  Utilities->CallLogPop(1509);
13455 }
13456 
13457 // ---------------------------------------------------------------------------
13458 
13459 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
13460 /*
13461  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
13462  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
13463 */
13464 {
13465  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
13466  int TempInt;
13467  int NumberOfPrefDirElements = 0;
13468 
13469  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13470  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
13471  {
13472  Utilities->CallLogPop(1152);
13473  return(false);
13474  }
13475  for(int x = 0; x < NumberOfPrefDirElements; x++)
13476  {
13477  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
13478  {
13479  Utilities->CallLogPop(1766);
13480  return(false);
13481  }
13482  VecFile >> TempInt;
13483  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
13484  {
13485  Utilities->CallLogPop(163);
13486  return(false);
13487  }
13488  VecFile >> TempInt;
13489  if((TempInt < -1) || (TempInt > 9)) // ELink
13490  {
13491  Utilities->CallLogPop(162);
13492  return(false);
13493  }
13494  VecFile >> TempInt;
13495  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
13496  {
13497  Utilities->CallLogPop(164);
13498  return(false);
13499  }
13500  VecFile >> TempInt;
13501  if((TempInt < -1) || (TempInt > 9)) // XLink
13502  {
13503  Utilities->CallLogPop(165);
13504  return(false);
13505  }
13506  VecFile >> TempInt;
13507  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
13508  {
13509  Utilities->CallLogPop(166);
13510  return(false);
13511  }
13512  VecFile >> TempInt;
13513  if((TempInt < -1) || (TempInt > 27)) // EXNumber
13514  {
13515  Utilities->CallLogPop(167);
13516  return(false);
13517  }
13518  VecFile >> TempInt;
13519  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
13520  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
13521  // ELinkPos, XLink, XLinkPos & EXNumber
13522  {
13523  Utilities->CallLogPop(168);
13524  return(false);
13525  }
13526  VecFile >> TempInt;
13527  if((TempInt != 0) && (TempInt != 1)) // RouteElement
13528  {
13529  Utilities->CallLogPop(1147);
13530  return(false);
13531  }
13532  VecFile >> TempInt;
13533  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
13534  {
13535  Utilities->CallLogPop(1510);
13536  return(false);
13537  }
13538  VecFile >> TempInt;
13539  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
13540  {
13541  Utilities->CallLogPop(1148);
13542  return(false);
13543  }
13544  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
13545  {
13546  Utilities->CallLogPop(1700);
13547  return(false);
13548  }
13549  }
13550  Utilities->CallLogPop(169);
13551  return(true);
13552 }
13553 
13554 // ---------------------------------------------------------------------------
13555 
13556 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
13557 {
13558  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
13559  int NumberOfPrefDirElements = PrefDirVector.size();
13560 
13561  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
13562  for(int y = 0; y < NumberOfPrefDirElements; y++)
13563  {
13564  VecFile << y << '\n'; // extra
13565  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n'; //When reloaded values for HLoc, VLoc & SpeedTag are derived from the TrackElement at TrackVectorPosition
13566  VecFile << PrefDirVector.at(y).ELink << '\n'; //so all 9 critical values are set
13567  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
13568  VecFile << PrefDirVector.at(y).XLink << '\n';
13569  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
13570  VecFile << PrefDirVector.at(y).EXNumber << '\n';
13571  VecFile << PrefDirVector.at(y).CheckCount << '\n';
13572  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
13573  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
13574  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
13575  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
13576  {
13577  VecFile << "************" << '\0' << '\n'; // marker
13578  }
13579  else
13580  {
13581  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13582  }
13583  }
13584  Utilities->CallLogPop(170);
13585 }
13586 
13587 // ---------------------------------------------------------------------------
13588 
13589 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
13590 {
13591  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
13592  int NumberOfSearchElements = SearchVector.size();
13593 
13594  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
13595  for(int y = 0; y < NumberOfSearchElements; y++)
13596  {
13597  VecFile << y << '\n'; // extra
13598  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
13599  VecFile << SearchVector.at(y).ELink << '\n';
13600  VecFile << SearchVector.at(y).ELinkPos << '\n';
13601  VecFile << SearchVector.at(y).XLink << '\n';
13602  VecFile << SearchVector.at(y).XLinkPos << '\n';
13603  VecFile << SearchVector.at(y).EXNumber << '\n';
13604  VecFile << SearchVector.at(y).CheckCount << '\n';
13605  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
13606  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
13607  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
13608  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
13609  {
13610  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13611  }
13612  else
13613  {
13614  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13615  }
13616  }
13617  Utilities->CallLogPop(1847);
13618 }
13619 
13620 // ---------------------------------------------------------------------------
13621 
13622 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
13623 /*
13624  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
13625  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
13626 */
13627 {
13628  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
13629  AnsiString(VLoc));
13630  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
13631 
13632  if(VecPos > -1)
13633  {
13634  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
13635  }
13636  else
13637  {
13638  Utilities->CallLogPop(171);
13639  return;
13640  }
13641  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
13642  if(VecPos > -1)
13643  {
13644  ErasePrefDirElementAt(3, VecPos);
13645  }
13646  else
13647  {
13648  Utilities->CallLogPop(172);
13649  return;
13650  }
13651  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
13652  if(VecPos > -1)
13653  {
13654  ErasePrefDirElementAt(4, VecPos);
13655  }
13656  else
13657  {
13658  Utilities->CallLogPop(173);
13659  return;
13660  }
13661  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
13662  if(VecPos > -1)
13663  {
13664  ErasePrefDirElementAt(5, VecPos);
13665  }
13666  else
13667  {
13668  Utilities->CallLogPop(174);
13669  return;
13670  }
13671  Utilities->CallLogPop(175);
13672 }
13673 
13674 // ---------------------------------------------------------------------------
13675 /*
13676  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
13677  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
13678 
13679  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
13680  in their place so that existing linkages will be preserved. At this stage this function is called to remove
13681  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
13682  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
13683  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
13684  PrefDirVector to correspond to the new track layout.
13685 
13686  {
13687  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
13688  if(PrefDirSize() == 0)
13689  {
13690  Utilities->CallLogPop(176);
13691  return;
13692  }
13693  for(int x=(PrefDirVector.size()-1);x>=0;x--)
13694  {
13695  int TV = PrefDirVector.at(x).TrackVectorPosition;
13696  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
13697  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
13698  if(Track->BlankElementAt(0, TV))
13699  {
13700  ErasePrefDirElementAt(6, x);
13701  }
13702  //if was a blankelement at x then ConnELink and ConnXLink both -1
13703  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
13704  {
13705  ErasePrefDirElementAt(7, x);
13706  }
13707  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
13708  //needs to be erased once, but if don't use 'else' then will erase two elements
13709  //since 'x' will correspond to the element after the first erased element
13710  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
13711  {
13712  ErasePrefDirElementAt(8, x);
13713  }
13714  }
13715  Utilities->CallLogPop(177);
13716  }
13717 */
13718 // ---------------------------------------------------------------------------
13719 
13720 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
13721 /*
13722  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
13723  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
13724 */
13725 {
13726  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
13727  bool AlreadyPresent, FoundFlag;
13728  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13729 
13730  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
13731  {
13732  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
13733  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13734  AlreadyPresent = false;
13735  if(FoundFlag)
13736  {
13737  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
13738  {
13739  AlreadyPresent = true;
13740  }
13741  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
13742  {
13743  AlreadyPresent = true;
13744  }
13745  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
13746  {
13747  AlreadyPresent = true;
13748  }
13749  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
13750  {
13751  AlreadyPresent = true;
13752  }
13753  }
13754  if(!AlreadyPresent)
13755  {
13756  StorePrefDirElement(4, TempElement);
13757  }
13758  }
13760  Utilities->CallLogPop(178);
13761 }
13762 /* earlier brute force search
13763  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
13764  {
13765  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
13766  bool AlreadyPresent = false;
13767  for(unsigned int y = 0;y<PrefDirSize();y++)
13768  {
13769  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
13770  }
13771  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
13772  }
13773 */
13774 
13775 // ---------------------------------------------------------------------------
13776 
13778 /*
13779  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
13780  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
13781  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
13782  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
13783  positions are likely to have changed, so this function is called to reset all the necessary connections and
13784  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
13785  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
13786  shouldn't have changed.
13787 */
13788 {
13789  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
13790  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13791  {
13792  bool FoundFlag;
13793  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13794  if(FoundFlag)
13795  {
13796  PrefDirVector.at(x).TrackVectorPosition = VecPos;
13797  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
13798  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
13799  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
13800  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
13801  for(unsigned int z = 0; z < 4; z++)
13802  {
13803  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
13804  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
13805  }
13806  }
13807  else
13808  {
13809  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
13810  }
13811  }
13812  Utilities->CallLogPop(179);
13813 }
13814 
13815 // ---------------------------------------------------------------------------
13816 
13818 /*
13819  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
13820 */
13821 {
13822  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
13823  bool DiscrepancyFound = false;
13824 
13825  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13826  {
13827  bool FoundFlag;
13828  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13829  if(FoundFlag)
13830  {
13831  TPrefDirElement PE = PrefDirVector.at(x);
13832  if(PE.TrackVectorPosition != VecPos)
13833  {
13834  DiscrepancyFound = true;
13835  break;
13836  }
13837  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13838  {
13839  DiscrepancyFound = true;
13840  break;
13841  }
13842  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13843  {
13844  DiscrepancyFound = true;
13845  break;
13846  }
13847  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
13848  {
13849  DiscrepancyFound = true;
13850  break;
13851  }
13852  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
13853  {
13854  DiscrepancyFound = true;
13855  break;
13856  }
13857  }
13858  else
13859  {
13860  DiscrepancyFound = true;
13861  }
13862  }
13863  if(DiscrepancyFound)
13864  {
13865  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
13866  ClearPrefDir(); // also clears multimap
13867  }
13868  Utilities->CallLogPop(1436);
13869 }
13870 
13871 // ---------------------------------------------------------------------------
13872 
13874 /*
13875  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
13876  return true for OK
13877 */
13878 {
13879  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
13880  bool DiscrepancyFound = false;
13881 
13882  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13883  {
13884  bool FoundFlag;
13885  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13886  if(FoundFlag)
13887  {
13888  TPrefDirElement PE = PrefDirVector.at(x);
13889  if(PE.TrackVectorPosition != VecPos)
13890  {
13891  DiscrepancyFound = true;
13892  }
13893  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13894  {
13895  DiscrepancyFound = true;
13896  break;
13897  }
13898  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13899  {
13900  DiscrepancyFound = true;
13901  break;
13902  }
13903  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
13904  {
13905  DiscrepancyFound = true;
13906  break;
13907  }
13908  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
13909  {
13910  DiscrepancyFound = true;
13911  break;
13912  }
13913  }
13914  else
13915  {
13916  DiscrepancyFound = true;
13917  }
13918  }
13919  Utilities->CallLogPop(1512);
13920  return(!DiscrepancyFound);
13921 }
13922 
13923 // ---------------------------------------------------------------------------
13924 
13925 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
13926 /*
13927  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
13928  turn and for the overall sizes.
13929 */
13930 {
13931  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
13932  bool FoundFlag = false;
13933  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
13934 
13935  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
13936  {
13937  TPrefDirElement CheckElement = PrefDirVector.at(a);
13938  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
13939  if(!FoundFlag)
13940  {
13941  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
13942  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
13943  }
13944  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
13945  {
13946  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
13947  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
13948  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
13949  }
13950  }
13951  if(PrefDirVector.size() != PrefDir4MultiMap.size())
13952  {
13953  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
13954  + " Caller=" + (AnsiString)Caller);
13955  }
13956  Utilities->CallLogPop(180);
13957 }
13958 
13959 // ---------------------------------------------------------------------------
13960 
13961 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
13962  int &PrefDirPos3)
13963 /*
13964  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
13965  two tracks for 4-entry elements. This function retrieves all elements that are present at a given H & V
13966  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
13967  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
13968  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
13969 */
13970 {
13971  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
13972  AnsiString(VLoc));
13973  THVPair PrefDirMapKeyPair;
13974 
13975  PrefDirPos0 = -1;
13976  PrefDirPos1 = -1;
13977  PrefDirPos2 = -1;
13978  PrefDirPos3 = -1;
13979  FoundFlag = false;
13980  PrefDirMapKeyPair.first = HLoc;
13981  PrefDirMapKeyPair.second = VLoc;
13982  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13983 
13984  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
13985  if(ItPair.first == ItPair.second) //none found
13986  {
13987  Utilities->CallLogPop(181);
13988  return;
13989  }
13990  else
13991  {
13992  FoundFlag = true;
13993  PrefDirPos0 = ItPair.first->second;
13994  ItPair.first++;
13995  if(ItPair.first == ItPair.second)
13996  {
13997  Utilities->CallLogPop(182); //only one found
13998  return;
13999  }
14000  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
14001  {
14002  PrefDirPos1 = ItPair.first->second;
14003  }
14004  ItPair.first++;
14005  if(ItPair.first == ItPair.second)
14006  {
14007  Utilities->CallLogPop(183); //2 found
14008  return;
14009  }
14010  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
14011  {
14012  PrefDirPos2 = ItPair.first->second;
14013  }
14014  ItPair.first++;
14015  if(ItPair.first == ItPair.second)
14016  {
14017  Utilities->CallLogPop(184); //3 found
14018  return;
14019  }
14020  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
14021  {
14022  PrefDirPos3 = ItPair.first->second; //4 found
14023  }
14024  }
14025  Utilities->CallLogPop(185);
14026 }
14027 
14028 // ---------------------------------------------------------------------------
14029 
14030 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
14031 { //not used after modified the pref dir checking function at v2.13.0
14032  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
14033  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
14034  try
14035  {
14036  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
14037  + "," + AnsiString(LinkNumberPos));
14038  bool FoundFlag;
14039  int PD0, PD1, PD2, PD3;
14040  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
14041  {
14042  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
14043  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
14044  PD0, PD1, PD2, PD3);
14045  if(!FoundFlag)
14046  {
14047  Utilities->CallLogPop(2282);
14048  return(false);
14049  }
14050  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
14051  {
14052  if(PD0 > -1)
14053  {
14054  if(PrefDirVector.at(PD0).TrackType == GapJump) //links to a gap and there is a pref dir set on it, doesn't matter about the link position
14055  {
14056  LinkedPrefDirVectorNumber = PD0;
14057  Utilities->CallLogPop(2283);
14058  return(true);
14059  }
14060  }
14061  if(PD1 > -1)
14062  {
14063  if(PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
14064  {
14065  LinkedPrefDirVectorNumber = PD1;
14066  Utilities->CallLogPop(2284);
14067  return(true);
14068  }
14069  }
14070  }
14071  if(PD0 > -1)
14072  {
14073  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
14074  {
14075  LinkedPrefDirVectorNumber = PD0;
14076  Utilities->CallLogPop(2285);
14077  return(true);
14078  }
14079  }
14080  if(PD1 > -1)
14081  {
14082  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
14083  {
14084  LinkedPrefDirVectorNumber = PD1;
14085  Utilities->CallLogPop(2286);
14086  return(true);
14087  }
14088  }
14089  if(PD2 > -1)
14090  {
14091  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
14092  {
14093  LinkedPrefDirVectorNumber = PD2;
14094  Utilities->CallLogPop(2287);
14095  return(true);
14096  }
14097  }
14098  if(PD3 > -1)
14099  {
14100  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
14101  {
14102  LinkedPrefDirVectorNumber = PD3;
14103  Utilities->CallLogPop(2288);
14104  return(true);
14105  }
14106  }
14107  LinkedPrefDirVectorNumber = -1;
14108  Utilities->CallLogPop(2289);
14109  return(false);
14110  }
14111  else //buffer or continuation, no link at position 0 but not a failure
14112  {
14113  LinkedPrefDirVectorNumber = -1;
14114  Utilities->CallLogPop(2290);
14115  return(true);
14116  }
14117  }
14118  catch(const Exception &e) //non error catch
14119  {
14120  LinkedPrefDirVectorNumber = -1;
14121  Utilities->CallLogPop(2291);
14122  return(false);
14123  }
14124 }
14125 
14126 // ---------------------------------------------------------------------------
14127 
14128 bool TOnePrefDir::FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
14129 { //not used after modified the pref dir checking function at v2.13.0
14130  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if finds same direction pref dir with linked
14131  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
14132  try
14133  {
14134  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingCompatiblePrefDir," + AnsiString(PrefDirVectorNumber)
14135  + "," + AnsiString(LinkNumberPos));
14136  bool FoundFlag;
14137  int PD0, PD1, PD2, PD3;
14138  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
14139  {
14140  GetVectorPositionsFromPrefDir4MultiMap(31, Track->TrackElementAt(1463, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
14141  Track->TrackElementAt(1464, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
14142  PD0, PD1, PD2, PD3);
14143  if(!FoundFlag)
14144  {
14145  Utilities->CallLogPop(2468);
14146  return(false);
14147  }
14148  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
14149  { //only PD0 or 1 will be set, else have track linking error that will be found earlier
14150  if(PD0 > -1)
14151  {
14152  if((PrefDirVector.at(PD0).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD0).XLink))
14153  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD0).ELink))))
14154  {
14155  LinkedPrefDirVectorNumber = PD0;
14156  Utilities->CallLogPop(2469);
14157  return(true);
14158  }
14159  }
14160  if(PD1 > -1)
14161  {
14162  if((PrefDirVector.at(PD1).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD1).XLink))
14163  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD1).ELink))))
14164  {
14165  LinkedPrefDirVectorNumber = PD1;
14166  Utilities->CallLogPop(2470);
14167  return(true);
14168  }
14169  }
14170  LinkedPrefDirVectorNumber = -1;
14171  Utilities->CallLogPop(2471);
14172  return(false);
14173  }
14174  if(PD0 > -1)
14175  {
14176  if((PrefDirVector.at(PD0).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD0).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14177  {
14178  LinkedPrefDirVectorNumber = PD0;
14179  Utilities->CallLogPop(2472);
14180  return(true);
14181  }
14182  }
14183  if(PD1 > -1)
14184  {
14185  if((PrefDirVector.at(PD1).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD1).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14186  {
14187  LinkedPrefDirVectorNumber = PD1;
14188  Utilities->CallLogPop(2473);
14189  return(true);
14190  }
14191  }
14192  if(PD2 > -1)
14193  {
14194  if((PrefDirVector.at(PD2).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD2).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14195  {
14196  LinkedPrefDirVectorNumber = PD2;
14197  Utilities->CallLogPop(2474);
14198  return(true);
14199  }
14200  }
14201  if(PD3 > -1)
14202  {
14203  if((PrefDirVector.at(PD3).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD3).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14204  {
14205  LinkedPrefDirVectorNumber = PD3;
14206  Utilities->CallLogPop(2475);
14207  return(true);
14208  }
14209  }
14210  LinkedPrefDirVectorNumber = -1;
14211  Utilities->CallLogPop(2476);
14212  return(false);
14213  }
14214  else //buffer or continuation, no link at position 0 but not a failure
14215  {
14216  LinkedPrefDirVectorNumber = -1;
14217  Utilities->CallLogPop(2477);
14218  return(true);
14219  }
14220  }
14221  catch(const Exception &e) //non error catch
14222  {
14223  LinkedPrefDirVectorNumber = -1;
14224  Utilities->CallLogPop(2478);
14225  return(false);
14226  }
14227 }
14228 
14229 // ---------------------------------------------------------------------------
14230 
14232 {
14233  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
14234  bool FoundFlag; //not used
14235  int PD0, PD1, PD2, PD3;
14236  //recover all PDs at the H & V of PDPtr
14237  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
14238 
14239  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
14240  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
14241 
14242  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
14243  {
14244  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
14245  {
14246  Utilities->CallLogPop(2292);
14247  return(true);
14248  }
14249  }
14250  if(PD1 > -1)
14251  {
14252  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
14253  {
14254  Utilities->CallLogPop(2293);
14255  return(true);
14256  }
14257  }
14258  if(PD2 > -1)
14259  {
14260  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
14261  {
14262  Utilities->CallLogPop(2294);
14263  return(true);
14264  }
14265  }
14266  if(PD3 > -1)
14267  {
14268  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
14269  {
14270  Utilities->CallLogPop(2295);
14271  return(true);
14272  }
14273  }
14274  Utilities->CallLogPop(2296);
14275  return(false);
14276 }
14277 
14278 // ---------------------------------------------------------------------------
14279 
14280 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
14281 /*
14282  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
14283 */
14284 {
14285  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
14286  PrefDirVector.push_back(LoadPrefDirElement);
14287  THVPair PrefDir4MultiMapKeyPair;
14288  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
14289 
14290  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
14291  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
14292  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
14293  PrefDir4MultiMapEntry.second = LastElementNumber(68);
14294  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
14295 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
14296  Utilities->CallLogPop(186);
14297 }
14298 
14299 // ---------------------------------------------------------------------------
14300 
14301 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
14302 /*
14303  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
14304  4MultiMap if they are greater than the erased value.
14305 */
14306 {
14307  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
14308  bool FoundFlag;
14309 
14310  if(!PrefDirVector.empty())
14311  {
14312  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
14313  if(!FoundFlag)
14314  {
14315  throw Exception("Failed to find PrefDir4MultiMap erase element");
14316  }
14317  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
14318  PrefDir4MultiMap.erase(EraseIt);
14319  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
14321  }
14322  Utilities->CallLogPop(187);
14323 }
14324 
14325 // ---------------------------------------------------------------------------
14326 
14327 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
14328 /*
14329  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
14330  4MultiMap if they are greater than the erased value.
14331 */
14332 {
14333  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
14334  AnsiString(ErasedElementNumber));
14335  if(!PrefDir4MultiMap.empty())
14336  {
14337  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
14338  {
14339  if(MapPtr->second > ErasedElementNumber)
14340  {
14341  MapPtr->second--;
14342  }
14343  }
14344  }
14345  Utilities->CallLogPop(1450);
14346 }
14347 
14348 // ---------------------------------------------------------------------------
14349 
14350 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
14351 /*
14352  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
14353  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
14354  nothing is found this is an error but the error message is given in the calling function.
14355 */
14356 {
14357  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
14358  FoundFlag = false;
14359  if(PrefDirVectorPosition >= PrefDirVector.size())
14360  {
14361  throw Exception("PrefDirVectorPosition out of range");
14362  }
14363  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
14364  THVPair PrefDir4MultiMapKeyPair;
14365 
14366  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
14367  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
14368  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
14369 
14370  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
14371  if(ItPair.first == ItPair.second)
14372  {
14373  Utilities->CallLogPop(188);
14374  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
14375  }
14376  else
14377  {
14378  if(ItPair.first->second == PrefDirVectorPosition)
14379  {
14380  FoundFlag = true;
14381  Utilities->CallLogPop(189);
14382  return(ItPair.first);
14383  }
14384  ItPair.first++;
14385  if(ItPair.first == ItPair.second)
14386  {
14387  Utilities->CallLogPop(190);
14388  return(ItPair.first); // nothing found
14389  }
14390  if(ItPair.first->second == PrefDirVectorPosition)
14391  {
14392  FoundFlag = true;
14393  Utilities->CallLogPop(191);
14394  return(ItPair.first);
14395  }
14396  ItPair.first++;
14397  if(ItPair.first == ItPair.second)
14398  {
14399  Utilities->CallLogPop(192);
14400  return(ItPair.first); // nothing found
14401  }
14402  if(ItPair.first->second == PrefDirVectorPosition)
14403  {
14404  FoundFlag = true;
14405  Utilities->CallLogPop(193);
14406  return(ItPair.first);
14407  }
14408  ItPair.first++;
14409  if(ItPair.first == ItPair.second)
14410  {
14411  Utilities->CallLogPop(194);
14412  return(ItPair.first); // nothing found
14413  }
14414  if(ItPair.first->second == PrefDirVectorPosition)
14415  {
14416  FoundFlag = true;
14417  Utilities->CallLogPop(195);
14418  return(ItPair.first);
14419  }
14420  }
14421  Utilities->CallLogPop(196);
14422  return(ItPair.first); // nothing found
14423 }
14424 
14425 // ---------------------------------------------------------------------------
14426 
14427 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
14428 /*
14429  Although there may be up to four entries at one H & V position this function gets just one. It is
14430  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
14431  at H & V.
14432 */
14433 {
14434  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
14435  THVPair PrefDir4MultiMapKeyPair;
14436 
14437  PrefDir4MultiMapKeyPair.first = HLoc;
14438  PrefDir4MultiMapKeyPair.second = VLoc;
14439  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
14440 
14441  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
14442  if(ItPair.first == ItPair.second) // nothing found
14443  {
14444  Utilities->CallLogPop(197);
14445  return(-1);
14446  }
14447  else
14448  {
14449  Utilities->CallLogPop(198);
14450  return(ItPair.first->second);
14451  }
14452 }
14453 
14454 // ---------------------------------------------------------------------------
14455 
14456 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
14457 {
14458  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
14459  bool ErasedFlag = false;
14460 
14461  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
14462  {
14463  if(PrefDirSize() == 0)
14464  {
14465  Utilities->CallLogPop(1511);
14466  return;
14467  }
14468  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
14469  {
14470  ErasedFlag = false;
14471  // use 'else' to ensure don't try to access an erased element
14472  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
14473  {
14474  ErasePrefDirElementAt(11, x);
14475  ErasedFlag = true;
14476  }
14477  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
14478  {
14479  ErasePrefDirElementAt(12, x);
14480  ErasedFlag = true;
14481  }
14482  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
14483  {
14484  ErasePrefDirElementAt(13, x);
14485  ErasedFlag = true;
14486  }
14487  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
14488  {
14489  ErasePrefDirElementAt(9, x);
14490  ErasedFlag = true;
14491  }
14492  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
14493  {
14494  ErasePrefDirElementAt(10, x);
14495  ErasedFlag = true;
14496  }
14497  if(!ErasedFlag)
14498  {
14499  // don't use 'else' here as may be more than one that need decrementing
14500  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
14501  {
14502  PrefDirVector.at(x).TrackVectorPosition--;
14503  }
14504  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
14505  {
14506  PrefDirVector.at(x).Conn[0]--;
14507  }
14508  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
14509  {
14510  PrefDirVector.at(x).Conn[1]--;
14511  }
14512  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
14513  {
14514  PrefDirVector.at(x).Conn[2]--;
14515  }
14516  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
14517  {
14518  PrefDirVector.at(x).Conn[3]--;
14519  }
14520  }
14521  }
14522  }
14523  Utilities->CallLogPop(1434);
14524 }
14525 
14526 // ---------------------------------------------------------------------------
14527 
14528 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
14529 {
14530  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
14531  OverallDistance = 0;
14532  OverallSpeedLimit = 0;
14533  LeadingPointsAtLastElement = false;
14534  if(PrefDirSize() == 0) // shouldn't be empty when this called
14535  {
14536  Utilities->CallLogPop(1491);
14537  return;
14538  }
14539  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
14540  {
14541  LeadingPointsAtLastElement = true;
14542  Utilities->CallLogPop(1492);
14543  return;
14544  }
14545  for(unsigned int x = 0; x < PrefDirSize(); x++)
14546  {
14547  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
14548  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
14549  {
14550  OverallDistance += PrefDirElement.Length23;
14551  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
14552  {
14553  if(x == 0)
14554  {
14555  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
14556  }
14557  else
14558  {
14559  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
14560  {
14561  OverallSpeedLimit = -1;
14562  }
14563  }
14564  }
14565  }
14566  else
14567  {
14568  OverallDistance += PrefDirElement.Length01;
14569  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
14570  {
14571  if(x == 0)
14572  {
14573  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
14574  }
14575  else
14576  {
14577  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
14578  {
14579  OverallSpeedLimit = -1;
14580  }
14581  }
14582  }
14583  }
14584  }
14585  Utilities->CallLogPop(1529);
14586 }
14587 
14588 // ---------------------------------------------------------------------------
14589 
14590 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
14591 {
14592  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
14593  if(PrefDirSize() == 0)
14594  {
14595  Utilities->CallLogPop(1564);
14596  return;
14597  }
14598  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14599  bool FoundFlag;
14601  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
14602 
14603  while(MMIT != PrefDir4MultiMap.end())
14604  {
14605  HLoc = MMIT->first.first;
14606  VLoc = MMIT->first.second;
14607  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14608  H = HLoc - Track->GetHLocMin();
14609  V = VLoc - Track->GetVLocMin();
14610  // always found in order, any missing have PrefDirPosx == -1
14611  if(PrefDirPos0 > -1)
14612  {
14613  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14614  }
14615  if(PrefDirPos1 > -1)
14616  {
14617  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
14618  }
14619  if(PrefDirPos2 > -1)
14620  {
14621  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
14622  }
14623  if(PrefDirPos3 > -1)
14624  {
14625  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
14626  }
14627  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
14628  {
14629  // need to plot all 4 in order to obtain all the direction graphics
14630  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14631  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14632  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14633  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14634  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14635  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14636  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
14637  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
14638  MMIT++;
14639  MMIT++;
14640  MMIT++;
14641  MMIT++;
14642  }
14643  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
14644  {
14645  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14646  {
14647  // 0 & 1 constitute the bidirectional PrefDir
14648  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14649  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14650  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14651  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14652  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
14653  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
14654  MMIT++;
14655  MMIT++;
14656  MMIT++;
14657  }
14658  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
14659  {
14660  // 0 & 2 constitute the bidirectional PrefDir
14661  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14662  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14663  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14664  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14665  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14666  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14667  MMIT++;
14668  MMIT++;
14669  MMIT++;
14670  }
14671  else
14672  {
14673  // 1 & 2 constitute the bidirectional PrefDir
14674  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14675  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14676  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14677  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14678  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14679  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14680  MMIT++;
14681  MMIT++;
14682  MMIT++;
14683  }
14684  }
14685  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14686  {
14687  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14688  {
14689  // 0 & 1 constitute the bidirectional PrefDir
14690  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14691  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14692  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14693  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14694  MMIT++;
14695  MMIT++;
14696  }
14697  else
14698  {
14699  // 2 unidirectional PrefDirs
14700  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14701  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14702  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14703  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14704  MMIT++;
14705  MMIT++;
14706  }
14707  }
14708  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
14709  {
14710  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14711  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14712  MMIT++;
14713  }
14714  }
14715  Utilities->CallLogPop(1565);
14716 }
14717 
14718 // ---------------------------------------------------------------------------
14719 
14720 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
14721 /*
14722  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
14723  level crossing, signals with wrong direction set, or buffers.
14724 */
14725 {
14726  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
14727  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14728  bool FoundFlag;
14730  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
14731 
14732  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
14733  ElementIn.VLoc)))
14734  {
14735  Utilities->CallLogPop(1982);
14736  return(false);
14737  }
14738  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at entry end, i.e. against preferred direction
14739  {
14740  Utilities->CallLogPop(1983);
14741  return(false);
14742  }
14743 /* if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal)) //ground signal allowed at v2.14.0
14744  {
14745  Utilities->CallLogPop(1995);
14746  return(false);
14747  }
14748 */
14749 // Now check that there is only a single prefdir set
14750  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14751 // always found in order, any missing have PrefDirPosx == -1
14752  if(PrefDirPos0 > -1)
14753  {
14754  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14755  }
14756  if(PrefDirPos1 > -1)
14757  {
14758  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
14759  }
14760  if(PrefDirPos2 > -1)
14761  {
14762  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
14763  }
14764  if(PrefDirPos3 > -1)
14765  {
14766  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
14767  }
14768  if(PrefDirPos3 > -1) // 4 found, all bidirectional
14769  {
14770  Utilities->CallLogPop(1984);
14771  return(false);
14772  }
14773  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
14774  {
14775  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
14776  {
14777  Utilities->CallLogPop(1985);
14778  return(false);
14779  }
14780  else
14781  {
14782  Utilities->CallLogPop(1986);
14783  return(true);
14784  }
14785  }
14786  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14787  {
14788  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
14789  {
14790  Utilities->CallLogPop(1987);
14791  return(false);
14792  }
14793  else
14794  {
14795  Utilities->CallLogPop(1988);
14796  return(true);
14797  }
14798  }
14799  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
14800  {
14801  if(PrefDirElement0.XLinkPos == EntryPos)
14802  {
14803  Utilities->CallLogPop(1989);
14804  return(false);
14805  }
14806  else
14807  {
14808  Utilities->CallLogPop(1990);
14809  return(true);
14810  }
14811  }
14812  else
14813  {
14814  Utilities->CallLogPop(1991);
14815  return(false); // none found
14816  }
14817 }
14818 
14819 // ---------------------------------------------------------------------------
14820 
14822 {
14823 /* //Added at v2.1.0
14824  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
14825  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
14826  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
14827  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
14828  and can be modelled better anyway.
14829 
14830  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
14831  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
14832  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14833  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14834  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14835  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14836 */
14837  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
14838  ElementIn.VLoc + "," + XLink);
14839  int TrackVecPos;
14840  bool TrackFoundFlag;
14841  TTrackElement TempTrackElement;
14842 
14843  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
14844  {
14845  Utilities->CallLogPop(2047);
14846  return(false);
14847  }
14848 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14849  if(XLink == 1)
14850  {
14851  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14852  if(TrackFoundFlag)
14853  {
14854  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
14855  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14856  {
14857  Utilities->CallLogPop(2048);
14858  return(true);
14859  }
14860  }
14861  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14862  if(TrackFoundFlag)
14863  {
14864  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
14865  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14866  {
14867  Utilities->CallLogPop(2049);
14868  return(true);
14869  }
14870  }
14871  }
14872 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14873  if(XLink == 3)
14874  {
14875  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14876  if(TrackFoundFlag)
14877  {
14878  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
14879  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14880  {
14881  Utilities->CallLogPop(2050);
14882  return(true);
14883  }
14884  }
14885  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14886  if(TrackFoundFlag)
14887  {
14888  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
14889  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14890  {
14891  Utilities->CallLogPop(2051);
14892  return(true);
14893  }
14894  }
14895  }
14896 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14897  if(XLink == 7)
14898  {
14899  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14900  if(TrackFoundFlag)
14901  {
14902  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
14903  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14904  {
14905  Utilities->CallLogPop(2052);
14906  return(true);
14907  }
14908  }
14909  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14910  if(TrackFoundFlag)
14911  {
14912  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
14913  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14914  {
14915  Utilities->CallLogPop(2053);
14916  return(true);
14917  }
14918  }
14919  }
14920 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14921  if(XLink == 9)
14922  {
14923  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14924  if(TrackFoundFlag)
14925  {
14926  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
14927  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14928  {
14929  Utilities->CallLogPop(2054);
14930  return(true);
14931  }
14932  }
14933  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14934  if(TrackFoundFlag)
14935  {
14936  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
14937  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14938  {
14939  Utilities->CallLogPop(2055);
14940  return(true);
14941  }
14942  }
14943  }
14944  Utilities->CallLogPop(2056);
14945  return(false);
14946 }
14947 
14948 // ---------------------------------------------------------------------------
14949 
14950 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
14951 {
14952 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
14953  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
14954  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
14955  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
14956  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
14957 */
14958  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
14960  bool FoundFlag, ContFlag, FoundElements = false;
14961  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14962  TPrefDirElement NextElement;
14963 
14964  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
14965  {
14966  LastIteratorValue++;
14967  ContFlag = false;
14968  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
14969  {
14970  continue;
14971  }
14972 /* if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal)) //ground signal start permitted at v2.14.0
14973  {
14974  continue;
14975  }
14976 */
14977 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
14978  // found a potential route start point
14979  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
14980  {
14981  continue;
14982  }
14983  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
14984  {
14985  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
14986  if(PDVIt->TrackType == Continuation)
14987  {
14988  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
14989  {
14990  continue;
14991  }
14992  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
14993  {
14994  continue;
14995  }
14996  }
14997  StartElement = *PDVIt;
14998 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
14999  // diverging track on which there was no pref dir. See below for 2 required changes.
15000  }
15001  else
15002  {
15003  continue;
15004  }
15005  // now track along until find a signal or continuation, checking validity for each element
15006  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
15007  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
15008  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15009  if(PrefDirPos0 == -1) // no continuing prefdir
15010  {
15011  continue;
15012  }
15013  bool NextElementFoundFlag = false;
15014  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15015  {
15016  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
15017  NextElementFoundFlag = true;
15018  }
15019  if(PrefDirPos1 > -1)
15020  {
15021  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15022  {
15023  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
15024  NextElementFoundFlag = true;
15025  }
15026  }
15027  if(PrefDirPos2 > -1)
15028  {
15029  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15030  {
15031  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
15032  NextElementFoundFlag = true;
15033  }
15034  }
15035  if(PrefDirPos3 > -1)
15036  {
15037  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15038  {
15039  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
15040  NextElementFoundFlag = true;
15041  }
15042  }
15043  if(!NextElementFoundFlag)
15044  {
15045  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
15046 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
15047  }
15048  while(true)
15049  {
15050  // check validity
15051  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
15052  {
15053  ContFlag = true;
15054  break;
15055  }
15056  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
15057  {
15058  ContFlag = true;
15059  break;
15060  }
15061  // check if in a route, providing not a signal, as a signal might be at the start of a route
15062  if(NextElement.TrackType != SignalPost)
15063  {
15064  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
15065  {
15066  ContFlag = true;
15067  break;
15068  }
15069  }
15070  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
15071  // can't be a gound signal as would have failed the validity test - can be at v2.14.0
15072  {
15073  EndElement = NextElement;
15074  break;
15075  }
15076  // get the next element in the sequence
15077  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
15078  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
15079  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15080  if(PrefDirPos0 == -1) // no continuing prefdir
15081  {
15082  ContFlag = true;
15083  break;
15084  }
15085  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15086  {
15087  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
15088  continue;
15089  }
15090  if(PrefDirPos1 > -1)
15091  {
15092  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15093  {
15094  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
15095  continue;
15096  }
15097  }
15098  if(PrefDirPos2 > -1)
15099  {
15100  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15101  {
15102  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
15103  continue;
15104  }
15105  }
15106  if(PrefDirPos3 > -1)
15107  {
15108  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15109  {
15110  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
15111  continue;
15112  }
15113  }
15114  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
15115  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
15116  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
15117  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
15118  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
15119  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
15120  {
15121  ContFlag = true;
15122  break;
15123  }
15124  else
15125  {
15126  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
15127  // could drop the bridge test but keep it to show the change history
15128  break;
15129 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
15130  }
15131  }
15132  if(ContFlag)
15133  {
15134  continue;
15135  }
15136  // else have start and end elements set & all elements valid, so set up the route segment
15137  FoundElements = true;
15138  break;
15139  }
15140  if(FoundElements)
15141  {
15142  Utilities->CallLogPop(1992);
15143  return(true);
15144  }
15145  else
15146  {
15147  Utilities->CallLogPop(1993);
15148  return(false);
15149  }
15150 }
15151 
15152 // ---------------------------------------------------------------------------
15153 // TOneRoute
15154 // ---------------------------------------------------------------------------
15155 
15156 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
15157 {
15158 /* General:
15159  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
15160  containing all the new elements to form the route. When complete, the SearchVector is converted into route
15161  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
15162  route will use automatic signals or not.
15163  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
15164  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
15165  elements, so additional work is needed to complete all their members before they are ready for conversion into
15166  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
15167  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
15168  ConvertAndAdd.......
15169 */
15170  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
15171  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
15172  ClearRoute();
15173  int TrackVectorPosition;
15174  TTrackElement TrackElement;
15175  TPrefDirElement FirstElement, LastElement;
15176 
15177  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
15178  {
15179  Utilities->CallLogPop(199);
15180  return(false);
15181  }
15182  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
15183  {
15184  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
15185  Utilities->CallLogPop(1996);
15186  return(false);
15187  }
15188  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
15189  {
15190  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
15191  Utilities->CallLogPop(200);
15192  return(false);
15193  }
15194  if(Track->IsLCAtHV(18, HLoc, VLoc))
15195  {
15196  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
15197  Utilities->CallLogPop(1909);
15198  return(false);
15199  }
15200 // check if selected a train & disallow if so
15201  if(TrackElement.TrainIDOnElement > -1)
15202  {
15203  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
15204  Utilities->CallLogPop(202);
15205  return(false);
15206  }
15207 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
15208  TPrefDirElement PrefDirElement;
15209  int LockedVectorNumber;
15210 
15211  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
15212  {
15213  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
15214  Utilities->CallLogPop(203);
15215  return(false);
15216  }
15217  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
15218  {
15219  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
15220  Utilities->CallLogPop(204);
15221  return(false);
15222  }
15224  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
15225 // signal in an autosig route & follow with a non-autosig route
15226 
15227  TPrefDirElement BlankElement;
15228 
15229  StartElement1 = BlankElement;
15230  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
15231 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
15232  bool InPrefDirFlag = false;
15233 
15234  bool FoundFlag;
15235  int PrefDirPos0 = -1;
15236  int PrefDirPos1 = -1;
15237  int PrefDirPos2 = -1;
15238  int PrefDirPos3 = -1;
15239 
15241  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15242  int PrefDirVecPos[4] =
15243  {
15244  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15245  };
15246 
15247  for(int x = 0; x < 4; x++)
15248  {
15249  int b = PrefDirVecPos[x];
15250  if(b > -1)
15251  {
15252  // only allow the appropriate exit route to be searched
15253  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
15254  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
15255  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
15256  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
15257  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
15258  {
15259  InPrefDirFlag = true;
15260  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
15261  if(AutoSigsFlag)
15262  {
15263  StartElement1.AutoSignals = true;
15264  }
15265  StartElement1.PrefDirRoute = true;
15266  }
15267  }
15268  }
15269 
15270  if(!InPrefDirFlag)
15271  {
15272  TrainController->StopTTClockMessage(12, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
15273  Utilities->CallLogPop(205);
15274  return(false);
15275  }
15276 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
15278  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15279 
15280  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
15281  {
15282  throw Exception("Selection in two routes - should never happen!");
15283  }
15284  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
15285  {
15286  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
15287  {
15288  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
15289  Utilities->CallLogPop(206);
15290  return(false);
15291  }
15292  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
15293  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
15294  {
15295  TrainController->StopTTClockMessage(14, "No forward connection from this position");
15296  Utilities->CallLogPop(207);
15297  return(false);
15298  }
15299  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
15300  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
15301  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15302  {
15303  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
15304  Utilities->CallLogPop(208);
15305  return(false);
15306  }
15307  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
15309  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
15310  if(AutoSigsFlag)
15311  {
15312  StartElement1.AutoSignals = true;
15313  }
15314  StartElement1.PrefDirRoute = true;
15316  Utilities->CallLogPop(209);
15317  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
15318  }
15319 
15320  else // no route started
15321  {
15322 // check if selected position is adjacent to start or end of an existing route and disallow
15323  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15324  {
15325  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
15326  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
15327  {
15328  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
15329  Utilities->CallLogPop(210);
15330  return(false);
15331  }
15332  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
15333  {
15334  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
15335  Utilities->CallLogPop(211);
15336  return(false);
15337  }
15338  }
15339 
15340 // check if it's adjacent to end of an existing route,
15341  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15342  {
15344  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
15345  {
15346  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
15347  Utilities->CallLogPop(212);
15348  return(false);
15349  }
15350  }
15351  SearchVector.push_back(StartElement1);
15352  Utilities->CallLogPop(213);
15353  return(true);
15354  }
15355 }
15356 
15357 // ---------------------------------------------------------------------------
15358 
15359 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
15360  IDInt &ReqPosRouteID, bool &PointsChanged)
15361 
15362 /*
15363  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
15364 
15365  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
15366  this being set to -1 for not used.
15367  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
15368  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
15369  Check correct type of element - signal/buffers/continuation.
15370  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
15371  EndElement2 corresponding to the 2 possible PrefDir elements).
15372  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
15373  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
15374  linked forward to another route.
15375  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
15376  for same position as start should cover this)
15377 
15378  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
15379  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
15380  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
15381  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
15382  If the search fails then return false.
15383  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
15384  in the SearchVector to ensure it's entered as part of the new route.
15385  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
15386  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
15387  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
15388  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
15389  so return false, with an appropriate message if ConsecSignalsRoute set.
15390 */
15391 
15392 {
15393  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
15394  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
15395  int EndPosition; // the position selected
15396  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
15397 
15398  Track->LCFoundInAutoSigsRoute = false;
15400  TotalSearchCount = 0;
15401  ReqPosRouteID = IDInt(-1); // default value for not used
15402  TTrackElement TrackElement;
15403  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
15404  // given element as can't select 2-track elements
15405  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
15406  {
15407  Utilities->CallLogPop(214);
15408  return(false);
15409  }
15410  if(Track->IsLCAtHV(19, HLoc, VLoc))
15411  {
15412  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
15413  Utilities->CallLogPop(1908);
15414  return(false);
15415  }
15416 // cancel selection if on original start element
15417  if(EndPosition == StartRoutePosition)
15418  {
15419  Utilities->CallLogPop(215);
15420  return(false);
15421  }
15422  if(AutoSigsFlag)
15423  {
15424  if(TrackElement.TrackType == Buffers)
15425  {
15426  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
15427  Utilities->CallLogPop(216);
15428  return(false);
15429  }
15430  }
15431  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
15432  {
15433  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
15434  Utilities->CallLogPop(217);
15435  return(false);
15436  }
15437 // check if train on element
15438  if(TrackElement.TrainIDOnElement > -1)
15439  {
15440  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
15441  Utilities->CallLogPop(219);
15442  return(false);
15443  }
15444 // disallow if not in EveryPrefDir & set EndElement(s)
15445  bool InPrefDirFlag = false;
15446 
15447  bool FoundFlag;
15448  int PrefDirPos0 = -1;
15449  int PrefDirPos1 = -1;
15450  int PrefDirPos2 = -1;
15451  int PrefDirPos3 = -1;
15452 
15453  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
15454  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15455  int PrefDirVecPos[4] =
15456  {
15457  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15458  };
15459 
15460  for(int x = 0; x < 4; x++)
15461  {
15462  int b = PrefDirVecPos[x];
15463  if(b > -1)
15464  {
15465  InPrefDirFlag = true;
15466  if(EndElement1.TrackVectorPosition == -1)
15467  {
15468  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
15469  }
15470  else
15471  {
15472  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
15473  }
15474  }
15475  }
15476  if(!InPrefDirFlag)
15477  {
15478  TrainController->StopTTClockMessage(23, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
15479  Utilities->CallLogPop(220);
15480  return(false);
15481  }
15482 // check if in an existing route - can't be a bridge so can use a simple 'find'
15483 // bool InRoute = false;
15485  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15486 
15487  if(RoutePair.first > -1)
15488  {
15489  if(RoutePair.second != 0) // not first element in existing route so no good
15490  {
15491  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
15492  Utilities->CallLogPop(221);
15493  return(false);
15494  }
15495  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
15496 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
15497  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
15498  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
15499  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
15500  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15501  {
15502  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
15503  Utilities->CallLogPop(222);
15504  return(false);
15505  }
15506  EndElement1 = RouteElement;
15507  EndElement2 = BlankElement; // only need the route element
15508  EndPosition = EndElement1.TrackVectorPosition;
15509  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
15510  }
15511 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
15512 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
15513 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
15514 
15515  if(EndElement1.HLoc >= StartElement1.HLoc)
15516  {
15518  SearchLimitHighH = EndElement1.HLoc + 15;
15519  }
15520  else
15521  {
15522  SearchLimitLowH = EndElement1.HLoc - 15;
15524  }
15525  if(EndElement1.VLoc >= StartElement1.VLoc)
15526  {
15528  SearchLimitHighV = EndElement1.VLoc + 15;
15529  }
15530  else
15531  {
15532  SearchLimitLowV = EndElement1.VLoc - 15;
15534  }
15535 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
15536  check & TotalSearchCounts check
15537  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
15538  {
15539  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
15540  Utilities->CallLogPop(1693);
15541  return false;
15542  }
15543 */
15544 // check if adjacent to start and disallow
15545  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15546  {
15548  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
15549 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
15550 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
15551  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15552  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15553  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
15554  {
15555  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
15556  Utilities->CallLogPop(223);
15557  return(false);
15558  }
15559 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
15560 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
15561  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
15562  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15563  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
15564  {
15565  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
15566  Utilities->CallLogPop(224);
15567  return(false);
15568  }
15569 // check if adjacent to end of a route & disallow
15571  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
15572  {
15573  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
15574  Utilities->CallLogPop(225);
15575  return(false);
15576  }
15577  }
15578 
15579 // check for same route as start element
15581  {
15582  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
15583  Utilities->CallLogPop(226);
15584  return(false);
15585  }
15586 // check for a looping route
15587  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
15588  {
15590  {
15591  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
15592  Utilities->CallLogPop(1844);
15593  return(false);
15594  }
15595  }
15596 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
15597 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
15598 // and don't want to add it again
15599  if(StartSelectionRouteID > -1)
15600  {
15601  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15602  AutoSigsFlag, false))
15603  {
15604  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
15605  if(PointsToBeChanged(5, NewFailedPointsTVPos))
15606  {
15607  if(NewFailedPointsTVPos > -1)
15608  {
15609  TTrackElement TE = Track->TrackElementAt(1478, NewFailedPointsTVPos);
15610  TrainController->StopTTClockMessage(97, "Points at " + TE.ElementID +
15611  " failed during route setting.");
15612  Utilities->CallLogPop(2488);
15613  return(false);
15614  }
15615  PointsChanged = true;
15616  }
15617  Utilities->CallLogPop(227);
15618  return(true);
15619  }
15620  else if(!Track->SuppressRouteFailMessage)
15621  {
15622  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
15624  Utilities->CallLogPop(228);
15625  return(false);
15626  }
15627  }
15628  else
15629  {
15630 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
15631 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
15632 
15633 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
15634 // note that a blank element will have XLinkPos set to -1
15635  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
15636  {
15637  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15638  AutoSigsFlag, false))
15639  {
15640  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
15641  if(PointsToBeChanged(6, NewFailedPointsTVPos))
15642  {
15643  if(NewFailedPointsTVPos > -1)
15644  {
15645  TTrackElement TE = Track->TrackElementAt(1480, NewFailedPointsTVPos);
15646  TrainController->StopTTClockMessage(99, "Points at " + TE.ElementID +
15647  " failed during route setting.");
15648  Utilities->CallLogPop(2490);
15649  return(false);
15650  }
15651  PointsChanged = true;
15652  }
15653  Utilities->CallLogPop(229);
15654  return(true);
15655  }
15656  else
15657  {
15659  {
15661  }
15662  Utilities->CallLogPop(230);
15663  return(false);
15664  }
15665  }
15666  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
15667  {
15668  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15669  AutoSigsFlag, false))
15670  {
15671  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
15672  if(PointsToBeChanged(7, NewFailedPointsTVPos))
15673  {
15674  if(NewFailedPointsTVPos > -1)
15675  {
15676  TTrackElement TE = Track->TrackElementAt(1482, NewFailedPointsTVPos);
15677  TrainController->StopTTClockMessage(101, "Points at " + TE.ElementID +
15678  " failed during route setting.");
15679  Utilities->CallLogPop(2492);
15680  return(false);
15681  }
15682  PointsChanged = true;
15683  }
15684  Utilities->CallLogPop(231);
15685  return(true);
15686  }
15687  else
15688  {
15690  {
15692  }
15693  Utilities->CallLogPop(232);
15694  return(false);
15695  }
15696  }
15697  // now start off in the best direction
15698  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
15699  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
15700  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
15701  // unless new problems are found.
15702  if(StartElement1.XLinkPos == BestPos)
15703  {
15704  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15705  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15706  AutoSigsFlag, false))
15707  {
15708  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
15709  if(PointsToBeChanged(8, NewFailedPointsTVPos))
15710  {
15711  if(NewFailedPointsTVPos > -1)
15712  {
15713  TTrackElement TE = Track->TrackElementAt(1484, NewFailedPointsTVPos);
15714  TrainController->StopTTClockMessage(103, "Points at " + TE.ElementID +
15715  " failed during route setting.");
15716  Utilities->CallLogPop(2494);
15717  return(false);
15718  }
15719  PointsChanged = true;
15720  }
15721  Utilities->CallLogPop(233);
15722  return(true);
15723  }
15724  else if(StartElement2.TrackVectorPosition > -1)
15725  {
15726  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15727  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15728  AutoSigsFlag, false))
15729  {
15730  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
15731  if(PointsToBeChanged(9, NewFailedPointsTVPos))
15732  {
15733  if(NewFailedPointsTVPos > -1)
15734  {
15735  TTrackElement TE = Track->TrackElementAt(1486, NewFailedPointsTVPos);
15736  TrainController->StopTTClockMessage(105, "Points at " + TE.ElementID +
15737  " failed during route setting.");
15738  Utilities->CallLogPop(2496);
15739  return(false);
15740  }
15741  PointsChanged = true;
15742  }
15743  Utilities->CallLogPop(234);
15744  return(true);
15745  }
15746  }
15747  }
15748  else if(StartElement2.TrackVectorPosition > -1)
15749  {
15750  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15751  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15752  AutoSigsFlag, false))
15753  {
15754  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
15755  if(PointsToBeChanged(10, NewFailedPointsTVPos))
15756  {
15757  if(NewFailedPointsTVPos > -1)
15758  {
15759  TTrackElement TE = Track->TrackElementAt(1488, NewFailedPointsTVPos);
15760  TrainController->StopTTClockMessage(107, "Points at " + TE.ElementID +
15761  " failed during route setting.");
15762  Utilities->CallLogPop(2498);
15763  return(false);
15764  }
15765  PointsChanged = true;
15766  }
15767  Utilities->CallLogPop(1857);
15768  return(true);
15769  }
15770  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15771  AutoSigsFlag, false))
15772  {
15773  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
15774  if(PointsToBeChanged(11, NewFailedPointsTVPos))
15775  {
15776  if(NewFailedPointsTVPos > -1)
15777  {
15778  TTrackElement TE = Track->TrackElementAt(1490, NewFailedPointsTVPos);
15779  TrainController->StopTTClockMessage(109, "Points at " + TE.ElementID +
15780  " failed during route setting.");
15781  Utilities->CallLogPop(2500);
15782  return(false);
15783  }
15784  PointsChanged = true;
15785  }
15786  Utilities->CallLogPop(1858);
15787  return(true);
15788  }
15789  }
15790  else if(StartElement1.XLinkPos == (1 - BestPos))
15791  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
15792  {
15793  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15794  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15795  AutoSigsFlag, false))
15796  {
15797  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
15798  if(PointsToBeChanged(12, NewFailedPointsTVPos))
15799  {
15800  if(NewFailedPointsTVPos > -1)
15801  {
15802  TTrackElement TE = Track->TrackElementAt(1492, NewFailedPointsTVPos);
15803  TrainController->StopTTClockMessage(111, "Points at " + TE.ElementID +
15804  " failed during route setting.");
15805  Utilities->CallLogPop(2502);
15806  return(false);
15807  }
15808  PointsChanged = true;
15809  }
15810  Utilities->CallLogPop(1864);
15811  return(true);
15812  }
15813  }
15814  }
15816  {
15818  }
15819  Utilities->CallLogPop(235);
15820  return(false);
15821 }
15822 
15823 // ---------------------------------------------------------------------------
15824 
15825 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
15826 {
15827  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
15828  if(PrefDirSize() == 0)
15829  {
15830  Utilities->CallLogPop(1704);
15831  return;
15832  }
15833  for(unsigned int x = 0; x < PrefDirSize(); x++)
15834  {
15835  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
15836  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
15837  {
15838  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15839  TempPrefDirElement.EXGraphicPtr);
15840  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
15841  {
15842  if(x == 0)
15843  {
15844  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15845  TempPrefDirElement.EntryDirectionGraphicPtr);
15846  }
15847  if(x == (PrefDirSize() - 1))
15848  {
15849  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15850  TempPrefDirElement.EntryDirectionGraphicPtr);
15851  }
15852  }
15853  }
15854  }
15855 
15856  Utilities->CallLogPop(1705);
15857 }
15858 
15859 // ---------------------------------------------------------------------------
15860 
15861 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
15862  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag, bool RecursiveCall)
15863 /*
15864  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
15865  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
15866  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
15867  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
15868  Return false if any element (apart from RequiredPosition) is on an existing route.
15869  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
15870 
15871  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
15872  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
15873  added during the function so as to leave it exactly as it was on entering, then return false).
15874  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
15875  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
15876  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
15877  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
15878  the route number that the searched-for element is the start of if any, and set to -1 if no
15879  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
15880  this unit, together with the ConsecSignals and AutoSigsFlag flags.
15881  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
15882  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
15883 
15884  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
15885  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
15886  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
15887  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
15888  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
15889  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
15890  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
15891  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
15892  or if train on element (unless a bridge & train on different track).
15893  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
15894  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
15895  a leading point where both trailing directions are in EveryPrefDir, if not fail.
15896  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
15897  AutoSignals member set if AutoSigsFlag set, then return true.
15898  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
15899 
15900  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
15901  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
15902  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
15903  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
15904  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
15905  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
15906  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
15907 
15908  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
15909  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
15910 */
15911 
15912 {
15913  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
15914  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
15915  AnsiString((short)AutoSigsFlag) + "," + AnsiString((short)RecursiveCall));
15916  int VectorCount = 0;
15917  if(!RecursiveCall) //added at v2.15.1
15918  {
15920  }
15921 
15922  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
15923 
15924 // check for a fouled diagonal for first element. Added for v1.3.2
15925  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
15926  {
15927  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
15928  {
15929  for(int x = 0; x < VectorCount; x++)
15930  {
15931  SearchVector.erase(SearchVector.end() - 1);
15932  }
15933  Utilities->CallLogPop(2043);
15934  return(false);
15935  }
15936  }
15937  bool FirstPass = true;
15938 
15939  while(true)
15940  {
15941  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
15942  {
15943  Track->LCFoundInAutoSigsRoute = true;
15944  }
15945  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
15946  {
15947  for(int x = 0; x < VectorCount; x++)
15948  {
15949  SearchVector.erase(SearchVector.end() - 1);
15950  }
15951  Utilities->CallLogPop(1926);
15952  return(false);
15953  }
15954  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
15955  {
15956  for(int x = 0; x < VectorCount; x++)
15957  {
15958  SearchVector.erase(SearchVector.end() - 1);
15959  }
15960  Utilities->CallLogPop(236);
15961  return(false);
15962  }
15963  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
15964  // reached a valid signal that isn't the required position, user should always select the next
15965  // signal in a route when ConsecSignals is true so have to fail
15966  // won't affect recurive searches as for them the first pass element is always a point
15967  {
15968  for(int x = 0; x < VectorCount; x++)
15969  {
15970  SearchVector.erase(SearchVector.end() - 1);
15971  }
15972  Utilities->CallLogPop(237);
15973  return(false);
15974  }
15975  FirstPass = false;
15976  int NextPosition = PrefDirElement.Conn[XLinkPos];
15977  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
15978  TPrefDirElement SearchElement(NextTrackElement);
15979  SearchElement.TrackVectorPosition = NextPosition;
15980  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
15981  SearchElement.ELinkPos = NextELinkPos;
15982  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
15983  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
15984  int NextXLinkPos;
15985  if(SearchElement.ELinkPos == 0)
15986  {
15987  NextXLinkPos = 1;
15988  }
15989  if(SearchElement.ELinkPos == 1)
15990  {
15991  NextXLinkPos = 0;
15992  }
15993  if(SearchElement.ELinkPos == 2)
15994  {
15995  NextXLinkPos = 3;
15996  }
15997  if(SearchElement.ELinkPos == 3)
15998  {
15999  NextXLinkPos = 2;
16000  }
16001  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
16002  {
16003  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
16004 // note that may be buffers, continuation or gap
16005  SearchElement.XLinkPos = NextXLinkPos;
16006  }
16007 // can't set XLink or XLinkPos yet if the element is a non-failed leading point.
16008 
16009 /* check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
16010  drop this as time-consuming, and RouteSearchLimit will stop the search if on a loop <--NO, need to keep in the case of crossovers as can reach
16011  element on opposite track and still find the required end point - causes error when adding to the Route"MultiMap (happened by chance when
16012  developing non-station named elements on points & crossovers). BUT need to speed up, don't use brute force search through all searchvector.
16013 
16014  just test 4-track elements & fail for crossover, points or bridge on same track, if 2-track then looping and searchlimit will stop - changed at v2.18.0
16015 */
16016  if((SearchElement.TrackType == Crossover) || (SearchElement.TrackType == Points))
16017  {
16018  for(unsigned int x = 0; x < SearchVector.size(); x++)
16019  {
16020  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc)) //same element
16021  {
16022  for(int x = 0; x < VectorCount; x++)
16023  {
16024  SearchVector.erase(SearchVector.end() - 1);
16025  }
16026  Utilities->CallLogPop(2653);
16027  return(false);
16028  }
16029  }
16030  }
16031  else if(SearchElement.TrackType == Bridge)
16032  {
16033  for(unsigned int x = 0; x < SearchVector.size(); x++)
16034  {
16035  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc) && //same element & same ELink
16036  (SearchElement.ELink == SearchVector.at(x).ELink))
16037  {
16038  for(int x = 0; x < VectorCount; x++)
16039  {
16040  SearchVector.erase(SearchVector.end() - 1);
16041  }
16042  Utilities->CallLogPop(2654);
16043  return(false);
16044  }
16045  }
16046  }
16047 
16048 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16049  TAllRoutes::TRouteElementPair SecondPair;
16051  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16052  if(RoutePair.first > -1)
16053  {
16054  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16055  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
16056  RoutePair.second).ELinkPos)))
16057  {
16058  // still OK if start of an expected route
16059  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
16060  {
16061  for(int x = 0; x < VectorCount; x++)
16062  {
16063  SearchVector.erase(SearchVector.end() - 1);
16064  }
16065  Utilities->CallLogPop(239);
16066  return(false); // only allow for start of an expected route
16067  }
16068  }
16069  }
16070  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16071  {
16072  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16073  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
16074  SecondPair.second).ELinkPos)))
16075  {
16076  // still OK if start of an expected route
16077  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
16078  {
16079  for(int x = 0; x < VectorCount; x++)
16080  {
16081  SearchVector.erase(SearchVector.end() - 1);
16082  }
16083  Utilities->CallLogPop(240);
16084  return(false); // only allow for start of an expected route
16085  }
16086  }
16087  }
16088 // check if a train on element, unless a bridge & train on different track
16089 // OK of same train as start element - no drop this
16090 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16091  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16092  {
16093  for(int x = 0; x < VectorCount; x++)
16094  {
16095  SearchVector.erase(SearchVector.end() - 1);
16096  }
16097  Utilities->CallLogPop(241);
16098  return(false);
16099  }
16100  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16101  {
16102  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
16103  {
16104  for(int x = 0; x < VectorCount; x++)
16105  {
16106  SearchVector.erase(SearchVector.end() - 1);
16107  }
16108  Utilities->CallLogPop(242);
16109  return(false);
16110  }
16111  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
16112  {
16113  for(int x = 0; x < VectorCount; x++)
16114  {
16115  SearchVector.erase(SearchVector.end() - 1);
16116  }
16117  Utilities->CallLogPop(243);
16118  return(false);
16119  }
16120  }
16121 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
16122  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16123  {
16124  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16125  {
16126  for(int x = 0; x < VectorCount; x++)
16127  {
16128  SearchVector.erase(SearchVector.end() - 1);
16129  }
16130  Utilities->CallLogPop(244);
16131  return(false);
16132  }
16133  }
16134 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
16135 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
16136  bool InPrefDirFlag = false;
16137  PrefDirElement1 = BlankElement;
16138  PrefDirElement2 = BlankElement;
16139 
16140  bool FoundFlag;
16141  int PrefDirPos0 = -1;
16142  int PrefDirPos1 = -1;
16143  int PrefDirPos2 = -1;
16144  int PrefDirPos3 = -1;
16146  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
16147  int PrefDirVecPos[4] =
16148  {
16149  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
16150  };
16151  for(int x = 0; x < 4; x++)
16152  {
16153  int b = PrefDirVecPos[x];
16154  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
16155  {
16156  InPrefDirFlag = true;
16157  if(PrefDirElement1.TrackVectorPosition == -1)
16158  {
16159  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
16160  }
16161  else
16162  {
16163  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
16164  }
16165  }
16166  }
16167  if(!InPrefDirFlag)
16168  {
16169  for(int x = 0; x < VectorCount; x++)
16170  {
16171  SearchVector.erase(SearchVector.end() - 1);
16172  }
16173  Utilities->CallLogPop(245);
16174  return(false);
16175  }
16176 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16177 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16178 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16180  {
16181  for(int x = 0; x < VectorCount; x++)
16182  {
16183  SearchVector.erase(SearchVector.end() - 1);
16184  }
16185  Utilities->CallLogPop(1690);
16186  return(false);
16187  }
16188 // check if found it
16189  if(SearchElement.TrackVectorPosition == RequiredPosition)
16190  {
16191 // need to ensure a signal/buffer/continuation
16192 // if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End)) dropped at v2.16.1 - may find element round a loop and appear invalid when in fact valid
16193  if((SearchElement.TrackType != SignalPost) && (SearchElement.TrackType != Buffers) && (SearchElement.TrackType != Continuation)) //added at v2.16.1
16194  {
16195  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
16197  for(int x = 0; x < VectorCount; x++)
16198  {
16199  SearchVector.erase(SearchVector.end() - 1);
16200  }
16201  QuitAllRecursiveSearchesFlag = true; //added at v2.15.1 (to stop several same messages being given)
16202  Utilities->CallLogPop(246);
16203  return(false);
16204  } // if((SearchElement.TrackType != SignalPost) &&.......
16205 //need to make sure it's in the right direction
16206  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End))
16207  { //condition added at v2.16.1
16208  for(int x = 0; x < VectorCount; x++)
16209  {
16210  SearchVector.erase(SearchVector.end() - 1);
16211  }
16212  Utilities->CallLogPop(2627);
16213  return(false);
16214  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal)......
16215 
16216  if(AutoSigsFlag)
16217  {
16218  PrefDirElement1.AutoSignals = true;
16219  }
16220  PrefDirElement1.PrefDirRoute = true;
16222  {
16224  {
16225  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
16227  }
16228  for(int x = 0; x < VectorCount; x++)
16229  {
16230  SearchVector.erase(SearchVector.end() - 1);
16231  }
16232  QuitAllRecursiveSearchesFlag = true; //added at v2.15.1
16233  Utilities->CallLogPop(1928);
16234  return(false);
16235  }
16236  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
16237  VectorCount++; // not really needed but include for tidyness
16238  TotalSearchCount++;
16239  if(!RecursiveCall && SignalHasFailed(0)) //added at v2.13.0. SignalHasFailed returns true if a signal somewhere on the route fails, route not set if so
16240  { //has to be the top level call (!RecursiveCall) as only then is the route sue to be set
16241  for(int x = 0; x < VectorCount; x++)
16242  {
16243  SearchVector.erase(SearchVector.end() - 1);
16244  }
16245  Utilities->CallLogPop(2522);
16246  return(false);
16247  }
16248  Utilities->CallLogPop(247);
16249  return(true);
16250  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
16251 
16252 // check if a buffer or continuation (end of search on this leg if not found by now)
16253  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16254  {
16255  for(int x = 0; x < VectorCount; x++)
16256  {
16257  SearchVector.erase(SearchVector.end() - 1);
16258  }
16259  Utilities->CallLogPop(248);
16260  return(false);
16261  }
16262 // check if SearchVector exceeds a size of RouteSearchLimitOneLeg (300)
16264  {
16265  for(int x = 0; x < VectorCount; x++)
16266  {
16267  SearchVector.erase(SearchVector.end() - 1);
16268  }
16269  Utilities->CallLogPop(1420);
16270  return(false);
16271  }
16272 //deal with failed points, added at v2.13.0
16273  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1518, SearchElement.TrackVectorPosition).Failed) //leading entry
16274  {
16275  if(Track->TrackElementAt(1519, SearchElement.TrackVectorPosition).Attribute == 0)
16276  {
16277  SearchElement.XLinkPos = 1;
16278  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16279  PrefDirElement1.XLinkPos = 1; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
16280  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
16281  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
16282  }
16283  else
16284  {
16285  SearchElement.XLinkPos = 3;
16286  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16287  PrefDirElement1.XLinkPos = 3; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
16288  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
16289  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
16290  }
16291  }
16292  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1520, SearchElement.TrackVectorPosition).Failed) //trailing entry
16293  {
16294  if((Track->TrackElementAt(1521, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
16295  {
16296  for(int x = 0; x < VectorCount; x++)
16297  {
16298  SearchVector.erase(SearchVector.end() - 1);
16299  }
16300  Utilities->CallLogPop(2514);
16301  return(false);
16302  }
16303  if((Track->TrackElementAt(1522, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
16304  {
16305  for(int x = 0; x < VectorCount; x++)
16306  {
16307  SearchVector.erase(SearchVector.end() - 1);
16308  }
16309  Utilities->CallLogPop(2515);
16310  return(false);
16311  }
16312  }
16313 // check if reached a non-failed leading point
16314  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !Track->TrackElementAt(1523, SearchElement.TrackVectorPosition).Failed)
16315  {
16316 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
16317  int SearchPos1 = SearchElement.Attribute + 1;
16318  int SearchPos2;
16319  if(SearchPos1 == 2)
16320  {
16321  SearchPos1++;
16322  }
16323  if(SearchPos1 == 1)
16324  {
16325  SearchPos2 = 3;
16326  }
16327  else
16328  {
16329  SearchPos2 = 1;
16330  }
16331  SearchElement.XLink = SearchElement.Link[SearchPos1];
16332  SearchElement.XLinkPos = SearchPos1;
16333  InPrefDirFlag = false;
16334  if(SearchElement.XLink == PrefDirElement1.XLink)
16335  {
16336  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
16337  InPrefDirFlag = true;
16338  }
16339  else if(SearchElement.XLink == PrefDirElement2.XLink)
16340  {
16341  SearchElement = PrefDirElement2;
16342  InPrefDirFlag = true;
16343  }
16344 // push element with XLink set to position [SearchPos1] if on a PrefDir
16345  if(InPrefDirFlag)
16346  {
16347 // check for a fouled diagonal for leading point for XLinkPos == 1)
16348  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16349  {
16350  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16351  {
16352  for(int x = 0; x < VectorCount; x++)
16353  {
16354  SearchVector.erase(SearchVector.end() - 1);
16355  }
16356  Utilities->CallLogPop(249);
16357  return(false);
16358  }
16359  }
16360  if(AutoSigsFlag)
16361  {
16362  SearchElement.AutoSignals = true;
16363  }
16364  SearchElement.PrefDirRoute = true;
16365  SearchVector.push_back(SearchElement);
16366  VectorCount++;
16367  TotalSearchCount++;
16368 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
16369  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16370  AutoSigsFlag, true))
16371  {
16373  {
16375  {
16376  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
16378  }
16379  for(int x = 0; x < VectorCount; x++)
16380  {
16381  SearchVector.erase(SearchVector.end() - 1);
16382  }
16383  Utilities->CallLogPop(1929);
16384  return(false);
16385  }
16386  if(!RecursiveCall && SignalHasFailed(1)) //added at v2.13.0
16387  {
16388  for(int x = 0; x < VectorCount; x++)
16389  {
16390  SearchVector.erase(SearchVector.end() - 1);
16391  }
16392  Utilities->CallLogPop(2523);
16393  return(false);
16394  }
16395  Utilities->CallLogPop(250);
16396  return(true);
16397  }
16398  else
16399  {
16400 // remove leading point with XLinkPos [1]
16401  if(!QuitAllRecursiveSearchesFlag) //added at v2.15.1
16402  {
16403  SearchVector.erase(SearchVector.end() - 1);
16404  VectorCount--;
16405  }
16406  else
16407  {
16408  for(int x = 0; x < VectorCount; x++)
16409  {
16410  SearchVector.erase(SearchVector.end() - 1);
16411  }
16412  Utilities->CallLogPop(2626);
16413  return(false);
16414  }
16415  }
16416  }
16417 // XLink set to position [SearchPos2]
16418  SearchElement.XLink = SearchElement.Link[SearchPos2];
16419  SearchElement.XLinkPos = SearchPos2;
16420  if(SearchElement.XLink == PrefDirElement1.XLink)
16421  {
16422  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
16423  }
16424  else if(SearchElement.XLink == PrefDirElement2.XLink)
16425  {
16426  SearchElement = PrefDirElement2;
16427  }
16428  else // failed to find a valid exit from the point
16429  {
16430  for(int x = 0; x < VectorCount; x++)
16431  {
16432  SearchVector.erase(SearchVector.end() - 1);
16433  }
16434  Utilities->CallLogPop(251);
16435  return(false);
16436  }
16437 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
16438  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16439  {
16440  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16441  {
16442  for(int x = 0; x < VectorCount; x++)
16443  {
16444  SearchVector.erase(SearchVector.end() - 1);
16445  }
16446  Utilities->CallLogPop(252);
16447  return(false);
16448  }
16449  }
16450 // push element with XLink set to position [SearchPos2]
16451  if(AutoSigsFlag)
16452  {
16453  SearchElement.AutoSignals = true;
16454  }
16455  SearchElement.PrefDirRoute = true;
16456  SearchVector.push_back(SearchElement);
16457  VectorCount++;
16458  TotalSearchCount++;
16459 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
16460  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16461  AutoSigsFlag, true))
16462  {
16464  {
16466  {
16467  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
16469  }
16470  for(int x = 0; x < VectorCount; x++)
16471  {
16472  SearchVector.erase(SearchVector.end() - 1);
16473  }
16474  Utilities->CallLogPop(1930);
16475  return(false);
16476  }
16477  if(!RecursiveCall && SignalHasFailed(2)) //added at v2.13.0
16478  {
16479  for(int x = 0; x < VectorCount; x++)
16480  {
16481  SearchVector.erase(SearchVector.end() - 1);
16482  }
16483  Utilities->CallLogPop(2524);
16484  return(false);
16485  }
16486  Utilities->CallLogPop(1592);
16487  return(true);
16488  }
16489  else
16490  {
16491  for(int x = 0; x < VectorCount; x++)
16492  {
16493  SearchVector.erase(SearchVector.end() - 1);
16494  }
16495  Utilities->CallLogPop(253);
16496  return(false);
16497  }
16498  } // if leading point
16499 
16500 // here if ordinary element or failed points, push it, inc vector & update PrefDirElement ready for next element on PrefDir
16501  SearchElement = PrefDirElement1;
16502  if(AutoSigsFlag)
16503  {
16504  SearchElement.AutoSignals = true;
16505  }
16506  SearchElement.PrefDirRoute = true;
16507  SearchVector.push_back(SearchElement);
16508  VectorCount++;
16509  TotalSearchCount++;
16510  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
16511  PrefDirElement = SearchElement;
16512  } // while(true)
16513 }
16514 
16515 // ---------------------------------------------------------------------------
16516 
16517 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
16518 {
16519 /*
16520  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
16521  and the new or extended route created from that. Hence action varies depending on whether
16522  it is a completely new route, or an extension of an existing route at the beginning or the end.
16523  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
16524  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
16525 
16526  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
16527  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
16528  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
16529  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
16530  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
16531  is decremented;
16532  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
16533  from the existing route, then enter the new route into the AllRoutesVector;
16534  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16535  then enter the new route into the AllRoutesVector.
16536 
16537  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
16538  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
16539  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
16540  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
16541  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
16542  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
16543  for the new route and return;
16544  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
16545  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
16546 
16547  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
16548  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
16549  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
16550 
16551 */
16552  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
16553  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
16554  if(SearchVector.size() < 1)
16555  {
16556  Utilities->CallLogPop(254);
16557  return;
16558  }
16560  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
16561  {
16562  Utilities->CallLogPop(255);
16563  return;
16564  }
16565  TAllRoutes::TLockedRouteClass LockedRouteObject;
16566 
16568  unsigned int TruncatePrefDirPosition = 0;
16569 
16570  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
16571 /* if have ReqPosRouteID:
16572  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
16573  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
16574  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
16575  the existing route, then enter the new route into the AllRoutesVector
16576  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16577  then enter the new route into the AllRoutesVector
16578 */
16579  {
16582  {
16583  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
16584  x++) // start at 1 as first element already in SearchVector
16585  {
16587  }
16588  // note that route numbers in map adjusted when ReqPos route cleared
16590  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
16591  // set during ClearRouteDuringRouteBuildingAt
16593  {
16596  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
16597  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
16598  }
16599  }
16601  {
16603  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
16604  }
16606  {
16607  SearchVector.pop_back();
16608  }
16609  }
16610  if(StartSelectionRouteID > -1)
16611 /* if have StartSelectionRouteID:
16612  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
16613  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
16614  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
16615  then add it to the start of the new route, then enter the new route into the AllRoutesVector
16616  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16617 */
16618  {
16620  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
16621  {
16624  {
16625  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
16626  for(unsigned int x = 0; x < SearchVector.size(); x++)
16627  {
16629  RouteNumber, GetFixedSearchElementAt(3, x));
16630  // find & store locked route truncate position in PrefDirVector for later use
16632  {
16633  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
16634  {
16635  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
16636  }
16637  }
16638  }
16640  {
16641  throw Exception("Error - failed to validate extended route for preferred route");
16642  }
16645  if(!AutoSigsFlag)
16646  {
16647  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
16648  }
16649  // now add the reinstated locked route if required and set signals accordingly
16651  {
16652  LockedRouteObject.RouteNumber = RouteNumber;
16653  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
16654  // now reset the signals for the locked route
16655  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
16656  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
16657  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
16658  {
16659  // return all signals to red in route section to be truncated
16660  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
16661  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
16662  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16663  {
16664  TrackElement.Attribute = 0;
16665  Track->PlotSignal(10, TrackElement, Display);
16666  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16667  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16668  }
16669  }
16670  }
16671  AllRoutes->CheckMapAndRoutes(1); // test
16672  Utilities->CallLogPop(256);
16673  return;
16674  }
16676  {
16679  RouteElement.AutoSignals = true;
16680  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
16681  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
16682  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
16683  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
16684  }
16685  }
16686  else
16687  {
16689  }
16690 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
16691 // AllRoutesVector hence nothing to do here
16692  }
16693  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
16694  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
16695  {
16696  throw Exception("Error - failed to validate single route for preferred route");
16697  }
16698  AllRoutes->StoreOneRoute(1, this);
16699  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
16700  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
16701  if(!AutoSigsFlag)
16702  {
16703  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
16704  }
16705  AllRoutes->CheckMapAndRoutes(2); // test
16706  Utilities->CallLogPop(257);
16707 }
16708 
16709 // ---------------------------------------------------------------------------
16710 
16711 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
16712 {
16713 /*
16714  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16715  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
16716  & ensure signal/buffers/continuation.
16717  Note that can't select ConsecSignalsRoute for non-preferred routes.
16718  Check if train on element & disallow.
16719  Set default values for retained parameters:-
16720  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
16721  StartSelectionRouteID = route that selection starts in if there is one;
16722 
16723  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
16724  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
16725  validity. This is just for safety reasons, the PrefDir values aren't used.
16726  StartElement1 & 2 are set to these PrefDirelements.
16727 
16728  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
16729 
16730  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
16731  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
16732  blank StartElement2 (only want to use the route element), then return true.
16733  Check if adjacent to start or end of an existing route & disallow if so.
16734  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
16735  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
16736  SetRemainingSearchVectorValues().
16737  Finally add the required element to the SearchVector & return true.
16738 
16739 */
16740  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
16741  AnsiString(VLoc) + "," + AnsiString((short)Callon));
16742  ClearRoute();
16743  int TrackVectorPosition;
16744  TTrackElement TrackElement;
16745  TPrefDirElement FirstElement, LastElement;
16746 
16747  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
16748  {
16749  Utilities->CallLogPop(258);
16750  return(false);
16751  }
16752  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
16753  {
16754  if(!Callon)
16755  {
16756  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
16757  }
16758 // makes later adjacent route checks too complicated
16759  Utilities->CallLogPop(259);
16760  return(false);
16761  }
16762  if(Track->IsLCAtHV(21, HLoc, VLoc))
16763  {
16764  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
16765  Utilities->CallLogPop(1910);
16766  return(false);
16767  }
16768 // check if selected a train & disallow if so
16769  if(TrackElement.TrainIDOnElement > -1)
16770  {
16771  if(!Callon)
16772  {
16773  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
16774  }
16775  Utilities->CallLogPop(260);
16776  return(false);
16777  }
16778 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
16779  TPrefDirElement PrefDirElement;
16780  int LockedVectorNumber;
16781 
16782  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
16783  {
16784  if(!Callon)
16785  {
16786  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
16787  }
16788  Utilities->CallLogPop(261);
16789  return(false);
16790  }
16791  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
16792  {
16793  if(!Callon)
16794  {
16795  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
16796  }
16797  Utilities->CallLogPop(262);
16798  return(false);
16799  }
16801 // AdjacentStartRouteNumber = -1;
16802  StartRoutePosition = TrackVectorPosition;
16803 // StartRouteSelectPosition = TrackVectorPosition;
16804 
16805  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
16806  TPrefDirElement PrefDirElement2(TrackElement);
16807 
16808  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
16809  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
16810  TPrefDirElement BlankElement;
16811 
16812  PrefDirElement1.ELinkPos = 0;
16813  PrefDirElement1.XLinkPos = 1;
16814  PrefDirElement1.ELink = PrefDirElement1.Link[0];
16815  PrefDirElement1.XLink = PrefDirElement1.Link[1];
16816  if(!(PrefDirElement1.EntryExitNumber()))
16817  {
16818  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
16819  // no need for bridge check as bridge selections not allowed
16820  }
16821  PrefDirElement1.CheckCount = 9;
16822  PrefDirElement2.ELinkPos = 1;
16823  PrefDirElement2.XLinkPos = 0;
16824  PrefDirElement2.ELink = PrefDirElement2.Link[1];
16825  PrefDirElement2.XLink = PrefDirElement2.Link[0];
16826  if(!(PrefDirElement2.EntryExitNumber()))
16827  {
16828  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
16829  }
16830  PrefDirElement2.CheckCount = 9; // both now set
16831 
16832 // set StartElements to the above PrefDirElements
16833  StartElement1 = PrefDirElement1;
16834  StartElement2 = PrefDirElement2;
16835 
16836 // no PrefDir check needed as doesn't need to be in a PrefDir
16837 
16838 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
16840  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
16841 
16842  if(RoutePair.first > -1)
16843  {
16844  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
16845  {
16846  if(!Callon)
16847  {
16848  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
16849  }
16850  Utilities->CallLogPop(263);
16851  return(false);
16852  }
16853  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
16854  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
16855  {
16856  if(!Callon)
16857  {
16858  TrainController->StopTTClockMessage(39, "No forward connection from this position");
16859  }
16860  Utilities->CallLogPop(264);
16861  return(false);
16862  }
16863  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
16864  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
16865  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
16866  {
16867  if(!Callon)
16868  {
16869  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
16870  }
16871  Utilities->CallLogPop(265);
16872  return(false);
16873  }
16874  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
16876  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
16877  StartElement2 = BlankElement; // only use the route element
16879  Utilities->CallLogPop(266);
16880  return(true); // all retained values set
16881  }
16882 
16883  else // selection not in an existing route
16884  {
16885 // check if it's adjacent to start of an an existing route,
16886  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16887  {
16888  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
16889  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
16890  {
16891  if(!Callon)
16892  {
16893  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
16894  }
16895  Utilities->CallLogPop(267);
16896  return(false);
16897  }
16898  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
16899  {
16900  if(!Callon)
16901  {
16902  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
16903  }
16904  Utilities->CallLogPop(268);
16905  return(false);
16906  }
16907  }
16908 // check if it's adjacent to end of an an existing route,
16909  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16910  {
16912  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
16913  {
16914  if(!Callon)
16915  {
16916  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
16917  }
16918  Utilities->CallLogPop(269);
16919  return(false);
16920  }
16921  }
16922  // not in a route or adjacent to start or end of a route
16923  // in this case reset all variable values to -1 & CheckCount to 4
16924  StartElement1.ELink = -1;
16925  StartElement1.ELinkPos = -1;
16926  StartElement1.XLink = -1;
16927  StartElement1.XLinkPos = -1;
16928  StartElement1.EXNumber = -1;
16929  StartElement1.CheckCount = 4; //Only covers the fixed values HLoc, VLoc, SpeedTag & TrackVectorPosition
16930  StartElement2 = BlankElement;
16931  SearchVector.push_back(StartElement1);
16932  Utilities->CallLogPop(270);
16933  return(true);
16934  }
16935 }
16936 
16937 // ---------------------------------------------------------------------------
16938 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
16939 
16940 /*
16941  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16942 
16943  Declare the following integers:-
16944  EndPosition - TrackVectorPosition for the selection;
16945  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
16946  Check if selection is a valid track element and set EndPosition.
16947  Cancel if select original start element, then check that not points, bridge or crossover.
16948  Check & fail if a train is present at the selection.
16949  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
16950  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
16951  No check needed for selection in EveryPrefDir.
16952  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
16953  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
16954  as don't need it if in a route.
16955  Check if selection adj to start or end of a route and disallow.
16956  Fail if select same route as starting route, though should already have failed earlier if this is so.
16957 
16958  If there's a StartSelectionRouteID then StartElement1 will be set to
16959  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
16960  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
16961  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
16962  to add the new route to the AllRoutesVectorPtr.
16963  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
16964  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
16965  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
16966  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
16967  the search vector values and return.
16968  If not returned yet then have failed to find the required element so return false with no message.
16969 
16970 */
16971 
16972 {
16973 // get EndPosition
16974  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
16975  AnsiString(VLoc));
16976  int EndPosition;
16977  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
16978 
16979  TotalSearchCount = 0;
16980  ReqPosRouteID = IDInt(-1); // for not used
16981  TTrackElement TrackElement;
16982  TPrefDirElement BlankElement;
16984 
16985  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
16986  {
16987  Utilities->CallLogPop(271);
16988  return(false);
16989  }
16990 // EndPosition = EndSelectPosition;
16991 // cancel selection if on original start element
16992  if(EndPosition == StartRoutePosition)
16993  {
16994  Utilities->CallLogPop(272);
16995  return(false);
16996  }
16997  if(Track->IsLCAtHV(22, HLoc, VLoc))
16998  {
16999  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
17000  Utilities->CallLogPop(1911);
17001  return(false);
17002  }
17003  if((TrackElement.TrackType == Points) && !Callon)
17004  {
17005  if(!Callon)
17006  {
17007  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
17008  }
17009 // makes later adjacent route checks too complicated
17010  Utilities->CallLogPop(273);
17011  return(false);
17012  }
17013  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
17014  {
17015  if(!Callon)
17016  {
17017  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
17018  }
17019 // makes later adjacent route checks too complicated
17020  Utilities->CallLogPop(1861);
17021  return(false);
17022  }
17023 // check if train on element
17024  if(TrackElement.TrainIDOnElement > -1)
17025  {
17026  if(!Callon)
17027  {
17028  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
17029  }
17030  Utilities->CallLogPop(274);
17031  return(false);
17032  }
17033 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
17034 // check passed)
17035  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
17036  TPrefDirElement EndElement2(TrackElement);
17037 
17038  EndElement1.TrackVectorPosition = EndPosition;
17039  EndElement2.TrackVectorPosition = EndPosition;
17040  EndElement1.ELinkPos = 0;
17041  EndElement1.XLinkPos = 1;
17042  EndElement1.ELink = EndElement1.Link[0];
17043  EndElement1.XLink = EndElement1.Link[1];
17044  if(!(EndElement1.EntryExitNumber()))
17045  {
17046  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
17047  }
17048  EndElement1.CheckCount = 9;
17049  EndElement2.ELinkPos = 1;
17050  EndElement2.XLinkPos = 0;
17051  EndElement2.ELink = EndElement2.Link[1];
17052  EndElement2.XLink = EndElement2.Link[0];
17053  if(!(EndElement2.EntryExitNumber()))
17054  {
17055  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
17056  }
17057  EndElement2.CheckCount = 9; // both now set
17058 
17059 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
17060 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
17061 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
17062 
17063  if(EndElement1.HLoc >= StartElement1.HLoc)
17064  {
17066  SearchLimitHighH = EndElement1.HLoc + 15;
17067  }
17068  else
17069  {
17070  SearchLimitLowH = EndElement1.HLoc - 15;
17072  }
17073  if(EndElement1.VLoc >= StartElement1.VLoc)
17074  {
17076  SearchLimitHighV = EndElement1.VLoc + 15;
17077  }
17078  else
17079  {
17080  SearchLimitLowV = EndElement1.VLoc - 15;
17082  }
17083 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
17084  check & TotalSearchCounts check
17085  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
17086  {
17087  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
17088  Utilities->CallLogPop(1694);
17089  return false;
17090  }
17091 */
17092 // don't need EveryPrefDir check for NonPreferredRoute
17093 
17094 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
17095 // bool InRoute = false;
17097  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
17098 
17099  if(RoutePair.first > -1)
17100  {
17101  if(RoutePair.second != 0) // not first element in existing route so no good
17102  {
17103  if(!Callon)
17104  {
17105  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
17106  }
17107  Utilities->CallLogPop(275);
17108  return(false);
17109  }
17110  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
17111 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
17112  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
17113  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
17114  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
17115  {
17116  if(!Callon)
17117  {
17118  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
17119  }
17120  Utilities->CallLogPop(276);
17121  return(false);
17122  }
17123  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
17124  EndElement2 = BlankElement; // only need the route element
17125  EndPosition = EndElement1.TrackVectorPosition;
17126  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
17127  }
17128 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
17129  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
17130  {
17131  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
17132  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
17133 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
17134 // && (AdjPosition != StartRoutePosition))
17135  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
17136  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
17137  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
17138  {
17139  if(!Callon)
17140  {
17141  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
17142  }
17143  Utilities->CallLogPop(277);
17144  return(false);
17145  }
17146 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
17147 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
17148  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
17149  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
17150  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
17151  (AdjPosition != StartRoutePosition))
17152  {
17153  if(!Callon)
17154  {
17155  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
17156  }
17157  Utilities->CallLogPop(278);
17158  return(false);
17159  }
17160 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
17162  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
17163  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
17164  {
17165  if(!Callon)
17166  {
17167  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
17168  }
17169  Utilities->CallLogPop(279);
17170  return(false);
17171  }
17172  }
17173 
17174 // check for same route as start element
17176  {
17177  if(!Callon)
17178  {
17179  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
17180  }
17181  Utilities->CallLogPop(280);
17182  return(false);
17183  }
17184 // check for a looping route
17185  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
17186  {
17188  {
17189  if(!Callon)
17190  {
17191  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
17192  }
17193  Utilities->CallLogPop(1845);
17194  return(false);
17195  }
17196  }
17197 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
17198 // so search from this element.
17199 
17200  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
17201 
17202  if(StartSelectionRouteID > -1)
17203  {
17204  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, false))
17205  {
17207  if(PointsToBeChanged(0, NewFailedPointsTVPos))
17208  {
17209  if(NewFailedPointsTVPos > -1)
17210  {
17211  TTrackElement TE = Track->TrackElementAt(1494, NewFailedPointsTVPos);
17212  TrainController->StopTTClockMessage(113, "Points at " + TE.ElementID +
17213  " failed during route setting.");
17214  Utilities->CallLogPop(2504);
17215  return(false);
17216  }
17217  PointsChanged = true;
17218  }
17219  Utilities->CallLogPop(281);
17220  return(true);
17221  }
17222  else
17223  {
17224  if(!Callon && !Track->SuppressRouteFailMessage)
17225  {
17227  }
17228  Utilities->CallLogPop(282);
17229  return(false);
17230  }
17231  }
17232  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
17233  // search on the 2 ways out of the element, which has to be a 2-ended element
17234  {
17235 // check if selection adjacent to start element and if so use that
17236  if(SearchVector.at(0).Conn[0] == EndPosition)
17237  {
17238  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID, false))
17239  {
17241  if(PointsToBeChanged(1, NewFailedPointsTVPos))
17242  {
17243  if(NewFailedPointsTVPos > -1)
17244  {
17245  TTrackElement TE = Track->TrackElementAt(1496, NewFailedPointsTVPos);
17246  TrainController->StopTTClockMessage(115, "Points at " + TE.ElementID +
17247  " failed during route setting.");
17248  Utilities->CallLogPop(2506);
17249  return(false);
17250  }
17251  PointsChanged = true;
17252  }
17253  Utilities->CallLogPop(283);
17254  return(true);
17255  }
17256  else
17257  {
17258  if(!Callon && !Track->SuppressRouteFailMessage)
17259  {
17261  }
17262  Utilities->CallLogPop(284);
17263  return(false);
17264  }
17265  }
17266  else if(SearchVector.at(0).Conn[1] == EndPosition)
17267  {
17268  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID, false))
17269  {
17271  if(PointsToBeChanged(2, NewFailedPointsTVPos))
17272  {
17273  if(NewFailedPointsTVPos > -1)
17274  {
17275  TTrackElement TE = Track->TrackElementAt(1498, NewFailedPointsTVPos);
17276  TrainController->StopTTClockMessage(117, "Points at " + TE.ElementID +
17277  " failed during route setting.");
17278  Utilities->CallLogPop(2508);
17279  return(false);
17280  }
17281  PointsChanged = true;
17282  }
17283  Utilities->CallLogPop(285);
17284  return(true);
17285  }
17286  else
17287  {
17288  if(!Callon && !Track->SuppressRouteFailMessage)
17289  {
17291  }
17292  Utilities->CallLogPop(286);
17293  return(false);
17294  }
17295  }
17296  // now start off in the best direction
17297  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
17298 
17299  if(SearchVector.at(0).Config[BestPos] != End)
17300  {
17301  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
17302  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID, false))
17303  {
17305  if(PointsToBeChanged(3, NewFailedPointsTVPos))
17306  {
17307  if(NewFailedPointsTVPos > -1)
17308  {
17309  TTrackElement TE = Track->TrackElementAt(1500, NewFailedPointsTVPos);
17310  TrainController->StopTTClockMessage(119, "Points at " + TE.ElementID +
17311  " failed during route setting.");
17312  Utilities->CallLogPop(2510);
17313  return(false);
17314  }
17315  PointsChanged = true;
17316  }
17317  Utilities->CallLogPop(287);
17318  return(true);
17319  }
17320  }
17321  if(SearchVector.at(0).Config[1 - BestPos] != End)
17322  {
17323  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
17324  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID, false))
17325  {
17327  if(PointsToBeChanged(4, NewFailedPointsTVPos))
17328  {
17329  if(NewFailedPointsTVPos > -1)
17330  {
17331  TTrackElement TE = Track->TrackElementAt(1502, NewFailedPointsTVPos);
17332  TrainController->StopTTClockMessage(121, "Points at " + TE.ElementID +
17333  " failed during route setting.");
17334  Utilities->CallLogPop(2512);
17335  return(false);
17336  }
17337  PointsChanged = true;
17338  }
17339  Utilities->CallLogPop(288);
17340  return(true);
17341  }
17342  }
17343  }
17344  if(!Callon && !Track->SuppressRouteFailMessage)
17345  {
17347  }
17348  Utilities->CallLogPop(289);
17349  return(false);
17350 }
17351 
17352 // ---------------------------------------------------------------------------
17353 
17354 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
17355 /*
17356  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
17357  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
17358  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
17359  Keep a count of entries in SearchVector during the current function call, so that this number can be
17360  erased for an unproductive branch search.
17361  First check (within the loop) whether XLink leads to an End & return false if so.
17362  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
17363  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
17364  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
17365  train on element (unless a bridge & train on different track), or if element
17366  fouls an existing diagonal route (except if element is a leading point - these checked later).
17367  Then check if found required element. If so save it & return true.
17368  If not the required element check if buffer or continuation, & if so erase all searchvector
17369  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
17370  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
17371  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
17372  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
17373  When return true have 8 items from CheckCount established, only waiting for EXNumber
17374 */
17375 {
17376  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
17377  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
17378  int VectorCount = 0;
17379 
17380 // check for a fouled diagonal for first element. Added for v1.3.2
17381  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
17382  (CurrentTrackElement.Link[XLinkPos] == 9))
17383  {
17384  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
17385  {
17386  for(int x = 0; x < VectorCount; x++)
17387  {
17388  SearchVector.erase(SearchVector.end() - 1);
17389  }
17390  Utilities->CallLogPop(2044);
17391  return(false);
17392  }
17393  }
17394  while(true)
17395  {
17396  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
17397  {
17398  for(int x = 0; x < VectorCount; x++)
17399  {
17400  SearchVector.erase(SearchVector.end() - 1);
17401  }
17402  Utilities->CallLogPop(1927);
17403  return(false);
17404  }
17405  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
17406  {
17407  for(int x = 0; x < VectorCount; x++)
17408  {
17409  SearchVector.erase(SearchVector.end() - 1);
17410  }
17411  Utilities->CallLogPop(290);
17412  return(false);
17413  }
17414  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
17415  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
17416  TPrefDirElement SearchElement(NextTrackElement);
17417  SearchElement.TrackVectorPosition = NextPosition;
17418  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
17419  SearchElement.ELinkPos = NextELinkPos;
17420  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
17421  int NextXLinkPos;
17422  if(SearchElement.ELinkPos == 0)
17423  {
17424  NextXLinkPos = 1;
17425  }
17426  if(SearchElement.ELinkPos == 1)
17427  {
17428  NextXLinkPos = 0;
17429  }
17430  if(SearchElement.ELinkPos == 2)
17431  {
17432  NextXLinkPos = 3;
17433  }
17434  if(SearchElement.ELinkPos == 3)
17435  {
17436  NextXLinkPos = 2;
17437  }
17438  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
17439  {
17440  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
17441  // but may be buffers, continuation or gap
17442  SearchElement.XLinkPos = NextXLinkPos;
17443  }
17444 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
17445 // can't set XLink or XLinkPos yet if the element is a leading point.
17446 
17447 /* check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
17448  drop this as time-consuming, and RouteSearchLimit will stop the search if on a loop <--NO, need to keep in the case of crossovers as can reach
17449  element on opposite track and still find the required end point - causes error when adding to the Route"MultiMap (happened by chance when
17450  developing non-station named elements on points & crossovers). BUT need to speed up, don't use brute force search through all searchvector.
17451 
17452  just test 4-track elements & fail for crossover, points or bridge on same track, if 2-track then looping and searchlimit will stop - changed at v2.18.0
17453 */
17454  if((SearchElement.TrackType == Crossover) || (SearchElement.TrackType == Points))
17455  {
17456  for(unsigned int x = 0; x < SearchVector.size(); x++)
17457  {
17458  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc)) //same element
17459  {
17460  for(int x = 0; x < VectorCount; x++)
17461  {
17462  SearchVector.erase(SearchVector.end() - 1);
17463  }
17464  Utilities->CallLogPop(2655);
17465  return(false);
17466  }
17467  }
17468  }
17469  else if(SearchElement.TrackType == Bridge)
17470  {
17471  for(unsigned int x = 0; x < SearchVector.size(); x++)
17472  {
17473  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc) && //same element & same ELink
17474  (SearchElement.ELink == SearchVector.at(x).ELink))
17475  {
17476  for(int x = 0; x < VectorCount; x++)
17477  {
17478  SearchVector.erase(SearchVector.end() - 1);
17479  }
17480  Utilities->CallLogPop(2656);
17481  return(false);
17482  }
17483  }
17484  }
17485 
17486 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
17487  TAllRoutes::TRouteElementPair SecondPair;
17489  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
17490  if(RoutePair.first > -1)
17491  {
17492  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
17493  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
17494  RoutePair.second).ELinkPos)))
17495  {
17496  // still OK if start of an expected route
17497  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
17498  {
17499  for(int x = 0; x < VectorCount; x++)
17500  {
17501  SearchVector.erase(SearchVector.end() - 1);
17502  }
17503  Utilities->CallLogPop(292);
17504  return(false); // only allow for start of an expected route
17505  }
17506  }
17507  }
17508  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
17509  {
17510  // OK if it's a bridge & routes on different tracks
17511  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
17512  SecondPair.second).ELinkPos)))
17513  {
17514  // still OK if start of an expected route
17515  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
17516  {
17517  for(int x = 0; x < VectorCount; x++)
17518  {
17519  SearchVector.erase(SearchVector.end() - 1);
17520  }
17521  Utilities->CallLogPop(293);
17522  return(false); // only allow for start of an expected route
17523  }
17524  }
17525  }
17526 // check if a train on element, unless a bridge & train on different track
17527 // OK of same train as start element - no, drop this
17528 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
17529  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
17530  {
17531  for(int x = 0; x < VectorCount; x++)
17532  {
17533  SearchVector.erase(SearchVector.end() - 1);
17534  }
17535  Utilities->CallLogPop(294);
17536  return(false);
17537  }
17538  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
17539  {
17540  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
17541  {
17542  for(int x = 0; x < VectorCount; x++)
17543  {
17544  SearchVector.erase(SearchVector.end() - 1);
17545  }
17546  Utilities->CallLogPop(295);
17547  return(false);
17548  }
17549  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
17550  {
17551  for(int x = 0; x < VectorCount; x++)
17552  {
17553  SearchVector.erase(SearchVector.end() - 1);
17554  }
17555  Utilities->CallLogPop(296);
17556  return(false);
17557  }
17558  }
17559 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
17560  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17561  {
17562  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17563  {
17564  for(int x = 0; x < VectorCount; x++)
17565  {
17566  SearchVector.erase(SearchVector.end() - 1);
17567  }
17568  Utilities->CallLogPop(297);
17569  return(false);
17570  }
17571  }
17572 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
17573 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
17574 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
17576  {
17577  for(int x = 0; x < VectorCount; x++)
17578  {
17579  SearchVector.erase(SearchVector.end() - 1);
17580  }
17581  Utilities->CallLogPop(1689);
17582  return(false);
17583  }
17584 // check if found it
17585  if(SearchElement.TrackVectorPosition == RequiredPosition)
17586  {
17587  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
17588  {
17589  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
17590  {
17591  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
17592  }
17593  else
17594  {
17595  SearchElement.XLinkPos = 1;
17596  }
17597 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
17598  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
17599  }
17600  SearchVector.push_back(SearchElement);
17601  VectorCount++; // not really needed but include for tidyness
17602  TotalSearchCount++;
17603  if(!RecursiveCall && SignalHasFailed(3)) //added at v2.13.0
17604  {
17605  for(int x = 0; x < VectorCount; x++)
17606  {
17607  SearchVector.erase(SearchVector.end() - 1);
17608  }
17609  Utilities->CallLogPop(2525);
17610  return(false);
17611  }
17612  Utilities->CallLogPop(298);
17613  return(true);
17614  }
17615 // Not the required element - check if a buffer or continuation
17616  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
17617  {
17618  for(int x = 0; x < VectorCount; x++)
17619  {
17620  SearchVector.erase(SearchVector.end() - 1);
17621  }
17622  Utilities->CallLogPop(299);
17623  return(false);
17624  }
17625 // check if SearchVector exceeds a size of RouteSearchLimitOneLeg (300)
17627  {
17628  for(int x = 0; x < VectorCount; x++)
17629  {
17630  SearchVector.erase(SearchVector.end() - 1);
17631  }
17632  Utilities->CallLogPop(1421);
17633  return(false);
17634  }
17635 //deal with failed points, added at v2.13.0
17636  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1524, SearchElement.TrackVectorPosition).Failed) //leading entry
17637  {
17638  if(Track->TrackElementAt(1525, SearchElement.TrackVectorPosition).Attribute == 0)
17639  {
17640  SearchElement.XLinkPos = 1;
17641  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
17642  }
17643  else
17644  {
17645  SearchElement.XLinkPos = 3;
17646  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
17647  }
17648  }
17649  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1526, SearchElement.TrackVectorPosition).Failed) //trailing entry
17650  {
17651  if((Track->TrackElementAt(1527, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
17652  {
17653  for(int x = 0; x < VectorCount; x++)
17654  {
17655  SearchVector.erase(SearchVector.end() - 1);
17656  }
17657  Utilities->CallLogPop(2533);
17658  return(false);
17659  }
17660  if((Track->TrackElementAt(1528, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
17661  {
17662  for(int x = 0; x < VectorCount; x++)
17663  {
17664  SearchVector.erase(SearchVector.end() - 1);
17665  }
17666  Utilities->CallLogPop(2534);
17667  return(false);
17668  }
17669  }
17670 
17671 // check if reached a non-failed leading point
17672  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !SearchElement.Failed)
17673  { //added !Failed condition at v2.13.0 to exclude failed points
17674 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
17675  int SearchPos1 = SearchElement.Attribute + 1;
17676  int SearchPos2;
17677  if(SearchPos1 == 2)
17678  {
17679  SearchPos1++;
17680  }
17681  if(SearchPos1 == 1)
17682  {
17683  SearchPos2 = 3;
17684  }
17685  else
17686  {
17687  SearchPos2 = 1;
17688  }
17689 // push element with XLink set to position [SearchPos1]
17690  SearchElement.XLink = SearchElement.Link[SearchPos1];
17691  SearchElement.XLinkPos = SearchPos1;
17692 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
17693  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17694  {
17695  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17696  {
17697  for(int x = 0; x < VectorCount; x++)
17698  {
17699  SearchVector.erase(SearchVector.end() - 1);
17700  }
17701  Utilities->CallLogPop(300);
17702  return(false);
17703  }
17704  }
17705  SearchVector.push_back(SearchElement);
17706  VectorCount++;
17707  TotalSearchCount++;
17708 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
17709 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
17710 // recursive search as has to be a TTrackElement for non-preferred route searches
17711  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID, true))
17712  {
17713  if(!RecursiveCall && SignalHasFailed(4)) //added at v2.13.0
17714  {
17715  for(int x = 0; x < VectorCount; x++)
17716  {
17717  SearchVector.erase(SearchVector.end() - 1);
17718  }
17719  Utilities->CallLogPop(2526);
17720  return(false);
17721  }
17722  Utilities->CallLogPop(301);
17723  return(true);
17724  }
17725  else
17726  {
17727 // remove leading point with XLinkPos [SearchPos1]
17728  SearchVector.erase(SearchVector.end() - 1);
17729  VectorCount--;
17730 // push element with XLink set to position [SearchPos2]
17731  SearchElement.XLink = SearchElement.Link[SearchPos2];
17732  SearchElement.XLinkPos = SearchPos2;
17733 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
17734  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17735  {
17736  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17737  {
17738  for(int x = 0; x < VectorCount; x++)
17739  {
17740  SearchVector.erase(SearchVector.end() - 1);
17741  }
17742  Utilities->CallLogPop(302);
17743  return(false);
17744  }
17745  }
17746  SearchVector.push_back(SearchElement);
17747  VectorCount++;
17748  TotalSearchCount++;
17749 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
17750  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID, true))
17751  {
17752  if(!RecursiveCall && SignalHasFailed(5)) //added at v2.13.0
17753  {
17754  for(int x = 0; x < VectorCount; x++)
17755  {
17756  SearchVector.erase(SearchVector.end() - 1);
17757  }
17758  Utilities->CallLogPop(2527);
17759  return(false);
17760  }
17761  Utilities->CallLogPop(303);
17762  return(true);
17763  }
17764  else
17765  {
17766  for(int x = 0; x < VectorCount; x++)
17767  {
17768  SearchVector.erase(SearchVector.end() - 1);
17769  }
17770  Utilities->CallLogPop(304);
17771  return(false);
17772  }
17773  }
17774  } // if leading point
17775 
17776 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
17777 // ready for next element on route
17778  SearchVector.push_back(SearchElement);
17779  VectorCount++;
17780  TotalSearchCount++;
17781  CurrentTrackElement = SearchElement;
17782  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
17783  } // while(true)
17784 }
17785 
17786 // ---------------------------------------------------------------------------
17787 
17789 
17790 /*
17791  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
17792  having all values set (since not necessarily on PrefDirs).
17793  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
17794  (if it was the start), so these are checked first and set if necessary. All elements now have
17795  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
17796  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
17797  to set the route colour and direction graphics.
17798 */
17799 
17800 {
17801  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
17802  if(SearchVector.size() == 0)
17803  {
17804  throw Exception("Error, SearchVector empty");
17805  }
17806 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
17807 // hence need to examine and update it if necessary
17808  TPrefDirElement SecondElement;
17809 
17810  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
17811  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
17812  // need above check or SecondElement will fail
17813  {
17814  SecondElement = SearchVector.at(1);
17815  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
17816  for(int x = 0; x < 4; x++)
17817  {
17818  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
17819  {
17820  if(SearchVector.at(0).XLink == -1) // i.e. not set
17821  {
17822  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
17823  SearchVector.at(0).XLinkPos = x;
17824  }
17825  int ELinkPos;
17826  if(SearchVector.at(0).XLinkPos == 0)
17827  {
17828  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
17829  }
17830  // linked to 1st searchvector element, & if XLink was set then x may not correspond
17831  if(SearchVector.at(0).XLinkPos == 1)
17832  {
17833  ELinkPos = 0;
17834  }
17835  if(SearchVector.at(0).XLinkPos == 2)
17836  {
17837  ELinkPos = 3;
17838  }
17839  if(SearchVector.at(0).XLinkPos == 3)
17840  {
17841  ELinkPos = 2;
17842  }
17843  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
17844  {
17845  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
17846  SearchVector.at(0).ELinkPos = ELinkPos;
17847  }
17848  break; // no point going any further
17849  }
17850  }
17851  }
17852  for(unsigned int x = 0; x < SearchVector.size(); x++)
17853  {
17854  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
17855 // set EXNumber
17856  if(!(SearchVector.at(x).EntryExitNumber()))
17857  {
17858  throw Exception("Error in EntryExitNumber 3");
17859  }
17860  SearchVector.at(x).CheckCount++;
17861 // all values now incorporated
17862  }
17863 
17864  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
17865 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
17866 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
17867  Utilities->CallLogPop(305);
17868 }
17869 
17870 // ---------------------------------------------------------------------------
17871 
17873 
17874 /*
17875  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
17876  AutoSigsRoute.
17877  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
17878  beginning or the end.
17879  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
17880  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
17881  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
17882  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
17883  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
17884  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
17885  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
17886 
17887  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
17888  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
17889  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
17890  route at the start.
17891 
17892  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
17893  for the new route and return.
17894 */
17895 
17896 {
17897  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
17898  AnsiString(ReqPosRouteID.GetInt()));
17899  if(SearchVector.size() < 1)
17900  {
17901  Utilities->CallLogPop(306);
17902  return;
17903  }
17904  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
17905  if(!ValidatePrefDir(6))
17906  {
17907  Utilities->CallLogPop(307);
17908  return;
17909  }
17910  TAllRoutes::TLockedRouteClass LockedRouteObject;
17911 
17913  unsigned int TruncatePrefDirPosition = 0;
17914 
17915  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
17916 /* if have ReqPosRouteID:
17917  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
17918  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
17919  then enter the new route into the AllRoutesVector
17920 */
17921  {
17923  {
17924  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
17925  x++) // start at 1 as first element already in SearchVector
17926  {
17928  }
17929  // note that route numbers in map adjusted when ReqPos route cleared
17931  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
17932  // set during ClearRouteDuringRouteBuildingAt)
17934  {
17937  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
17938  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
17939  }
17940  }
17942  {
17943  SearchVector.pop_back();
17944  }
17945  }
17946  if(StartSelectionRouteID > -1)
17947 /* if have StartSelectionRouteID:
17948  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
17949  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
17950 */
17951  {
17953  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
17954  {
17956  {
17957  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
17958  for(unsigned int x = 0; x < SearchVector.size(); x++)
17959  {
17961  RouteNumber, GetFixedSearchElementAt(7, x));
17962  // find & store locked route truncate position in PrefDirVector for later use
17964  {
17965  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
17966  {
17967  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
17968  }
17969  }
17970  }
17972  {
17973  throw Exception("Failed to validate extended route for nonpreferred route");
17974  }
17977  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
17978  // now add the reinstated locked route if required and set signals accordingly
17979  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
17980  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
17981  // that I haven't thought of
17983  {
17984  LockedRouteObject.RouteNumber = RouteNumber;
17985  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
17986  // now reset the signals for the locked route
17987  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
17988  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
17989  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
17990  {
17991  // return all signals to red in route section to be truncated
17992  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
17993  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
17994  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17995  {
17996  TrackElement.Attribute = 0;
17997  Track->PlotSignal(11, TrackElement, Display);
17998  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17999  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
18000  }
18001  }
18002  }
18003  AllRoutes->CheckMapAndRoutes(3); // test
18004  Utilities->CallLogPop(308);
18005  return;
18006  }
18007  }
18008  else
18009  {
18011  }
18012 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
18013 // hence nothing to do here
18014  }
18015  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
18016  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
18017  {
18018  throw Exception("Failed to validate single route for nonpreferred route");
18019  }
18020  AllRoutes->StoreOneRoute(2, this);
18021  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
18022  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
18023  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
18024  AllRoutes->CheckMapAndRoutes(4); // test
18025  Utilities->CallLogPop(309);
18026 }
18027 
18028 // ---------------------------------------------------------------------------
18029 
18030 void TOneRoute::SetRoutePoints(int Caller) const
18031 /*
18032  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
18033  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
18034  when they were created.
18035 */
18036 {
18037  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
18038  if(!PrefDirVector.empty())
18039  {
18040  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18041  {
18042  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) //1=straight trailing
18043  {
18044  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
18045  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
18046  }
18047  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) //3=diverging trailing
18048  {
18049  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
18050  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
18051  }
18052  }
18053  }
18054  Utilities->CallLogPop(327);
18055 }
18056 
18057 // ---------------------------------------------------------------------------
18058 
18059 void TOneRoute::SetRouteSignals(int Caller) const
18060 // Used for new train additions in AddTrain and in route setting, major changes at v2.17.0
18061 
18062 {
18063  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
18064  if(!PrefDirVector.empty())
18065  {
18066  int RouteNumber;
18067  int Attribute = 0;
18068  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
18069  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
18070  if(RouteType != TAllRoutes::NoRoute)
18071  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
18072  {
18073  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
18074  }
18075  }
18076  Utilities->CallLogPop(1720);
18077 }
18078 
18079 // ---------------------------------------------------------------------------
18080 
18081 bool TOneRoute::PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
18082 {
18083  //true if at any point in SearchVector points have to be changed,
18084  //changed to give every point to be changed in route to have a chance of failure, but if one fails then don't look any further
18085  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
18086  NewFailedPointsTVPos = -1; //default value for no new failure
18087  bool PointsChanged = false;
18088  if(!SearchVector.empty())
18089  {
18090  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
18091  {
18092  TTrackElement &TE = Track->TrackElementAt(1504, SearchPtr->TrackVectorPosition);
18093  //check for an existing failed point where needs to change to make the route
18094  int Attr = TE.Attribute;
18095  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=want to go straight
18096  {
18097  if(Attr == 1) //currently set to diverge
18098  {
18099  //here add new failure possibility at v2.13.0
18100  if(Utilities->FailureMode != FNil)
18101  {
18102  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
18103  {
18105  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
18106  IFE.TVPos = NewFailedPointsTVPos;
18107  TE.Failed = true;
18108  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
18110  TE.SpeedLimit01 = 10; //values while failed
18111  TE.SpeedLimit23 = 10;
18112  Display->WarningLog(13, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
18113  PerfLogForm->PerformanceLog(36, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
18114  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18115  //set repair time, random value in minutes between 10 and 179
18116  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
18117  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18118  IFE.RepairTime = RepairTime;
18120  Track->FailedPointsVector.push_back(IFE);
18121  Utilities->CallLogPop(1717);
18122  return(true); //return so only allow one failure per route
18123  }
18124  }
18125  PointsChanged = true; //this is used for setting the flash time
18126  }
18127  }
18128  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=want to diverge
18129  {
18130  if(Attr == 0) //currently set to go straight
18131  {
18132  //here add failure possibility at v2.13.0
18133  if(Utilities->FailureMode != FNil)
18134  {
18135  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
18136  {
18138  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
18139  IFE.TVPos = NewFailedPointsTVPos;
18140  TE.Failed= true;
18141  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
18143  TE.SpeedLimit01 = 10; //values while failed
18144  TE.SpeedLimit23 = 10;
18145  Display->WarningLog(14, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
18146  PerfLogForm->PerformanceLog(37, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
18147  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18148  //set repair time, random value in minutes between 10 and 179
18149  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime);
18150  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18151  IFE.RepairTime = RepairTime;
18153  Track->FailedPointsVector.push_back(IFE);
18154  Utilities->CallLogPop(1718);
18155  return(true); //only allow one failure per route
18156  }
18157  }
18158  PointsChanged = true;
18159  }
18160  }
18161  }
18162  }
18163  Utilities->CallLogPop(1719);
18164  return(PointsChanged);
18165 }
18166 
18167 // ---------------------------------------------------------------------------
18168 
18169 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute, int StartPos) const
18170 /* //added StartPos at v2.17.0 so it starts in the current route
18171 
18172  Only called by SetRearwardsSignalsReturnFalseForTrainInRear
18173 
18174  Works forward through the route from & including StartPos until finds:-
18175  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18176  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
18177  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
18178  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18179  (e) forward-facing non-ground signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (non-ground sig condition added at v2.14.0)
18180  (e1) forward-facing ground signal with attribute 0 - Attribute = ground signal attribute + 1 (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
18181  (e2) forward-facing ground signal with attribute > 0 - Attribute = ground signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
18182  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18183  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
18184 */
18185 {
18186  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
18187  Attribute = 0;
18188  NextForwardLinkedRouteNumber = -1;
18189  for(unsigned int x = StartPos; x < PrefDirSize(); x++)
18190  {
18191  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
18192  if(PrefDirVector.at(x).TrackType == Bridge)
18193  {
18194  if(PrefDirVector.at(x).XLinkPos < 2)
18195  {
18196  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18197  }
18198  else
18199  {
18200  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18201  }
18202  }
18203  if(TrainID != -1)
18204  {
18205  Utilities->CallLogPop(328); //attribute still 0
18206  return(true);
18207  }
18208  if(PrefDirVector.at(x).TrackType == Buffers)
18209  {
18210  Attribute = 1;
18211  Utilities->CallLogPop(329);
18212  return(true);
18213  }
18214  if(PrefDirVector.at(x).TrackType == Continuation)
18215  {
18216  Attribute = 3;
18217  Utilities->CallLogPop(330);
18218  return(true);
18219  }
18220  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
18221  {
18222  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
18223  {
18224  Attribute = 0;
18225  Utilities->CallLogPop(1950);
18226  return(true);
18227  }
18228  }
18229  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
18230  {
18231  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute; //added at v2.14.0
18232  if((PrefDirVector.at(x).SigAspect != TTrackElement::GroundSignal) || (Attribute == 0))//added at v2.14.0
18233  {
18234  Attribute++;
18235  }
18236  if(Attribute > 3)
18237  {
18238  Attribute = 3;
18239  }
18240  Utilities->CallLogPop(331);
18241  return(true);
18242  }
18243  if(x == PrefDirSize() - 1) //end element and not signal, buffer, continuation or LC, and no train on element
18244  {
18245  TPrefDirElement LastElement = GetFixedPrefDirElementAt(268, x);
18246  NextForwardLinkedRouteNumber = -1;
18247  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(42, Track->TrackElementAt(1579, LastElement.TrackVectorPosition).Conn[LastElement.XLinkPos], Track->TrackElementAt(1580, LastElement.TrackVectorPosition).ConnLinkPos[LastElement.XLinkPos], NextForwardLinkedRouteNumber);
18248 //the above returns a route (or no route) but LinkPos can be entry or exit, so still need to know it's the entry link for the follow-on route to be valid
18249  if(!(RouteType == TAllRoutes::NoRoute)) //probably a forward route but still need to check if it's linked
18250  {
18251  TPrefDirElement NewRoutePDE = AllRoutes->GetFixedRouteAt(227, NextForwardLinkedRouteNumber).GetFixedPrefDirElementAt(269, 0); //0 is start position
18252  if(NewRoutePDE.ELinkPos == Track->TrackElementAt(1581, LastElement.TrackVectorPosition).ConnLinkPos[LastElement.XLinkPos]) //if it's not then route not linked so there's no forward route
18253  {
18254  Attribute = 0;
18255  Utilities->CallLogPop(332);
18256  return(false);
18257  }
18258  //else there is no forward route, so return true with attribute still 0
18259  }
18260  //else there is no forward route, so return true with attribute still 0
18261  }
18262  }
18263  Utilities->CallLogPop(333); //
18264  return(true);
18265 }
18266 
18267 // ---------------------------------------------------------------------------
18268 
18269 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrainInRear(int Caller, int &Attribute, int PrefDirVectorStartPosition, bool SkipForwardLook) const
18270 /* Major changes at v2.17.0
18271  This function is only called by TAllRoutes::SetAllRearwardsSignals.
18272 
18273  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
18274  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
18275  rearward search, first search forwards (unless SkipForwardLook true) from the PrefDirVectorStartPosition + 1 (may be in a forward route -
18276  see FindForwardTargetSignalAttribute) in case the end of the route is a buffer, continuation, or something else that requires Attribute
18277  to be modified and modify the Attribute accordingly UNLESS (a) train or closed LC present between PrefDirVectorStartPosition & end;
18278  (b) route in ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals),
18279  or (c) truncating a route.
18280 
18281  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
18282  signal or something else that requires Attribute to change. If find a signal set its Attribute to the current Attribute value up to a maximum
18283  of 3, and replot the signal as well as the required route and direction (if required) graphics, then increment Attribute up to a max. of 3
18284  [addition at v2.9.2: if signal or element beyond it is in a locked route then set signal to red & change Attribute to 0 - this fault reported
18285  by Simon Banham 21/07/21 as an image]. and continue working backwards for the next signal (or train - return false as before) and so on.
18286  On completion Attribute is passed back from the function as a reference. If no train is found before the beginning of the route is reached
18287  the function returns true.
18288 
18289  In setting signals skip the first position if it's a signal and if truncating (can only truncate to signal if route is unrestricted) - otherwise
18290  the truncated signal counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
18291 */
18292 {
18293  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrainInRear," + AnsiString(Attribute) + "," +
18294  AnsiString(PrefDirVectorStartPosition));
18295  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
18296  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
18297 // if no train or closed LC between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
18298 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
18299 
18300  if(!PrefDirVector.empty())
18301  {
18302  if(!SkipForwardLook)
18303  {
18304  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
18305  {
18306  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
18307  if(PrefDirPtr->TrackType == Bridge)
18308  {
18309  if(PrefDirPtr->XLinkPos < 2)
18310  {
18311  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18312  }
18313  else
18314  {
18315  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18316  }
18317  }
18318  if(TrainID != -1)
18319  {
18320  SkipForwardLook = true;
18321  break;
18322  }
18323  }
18324  }
18325 
18327  {
18328  SkipForwardLook = true;
18329  }
18330 
18331  int NextForwardLinkedRouteNumber = -1;
18332  if((unsigned int)PrefDirVectorStartPosition == PrefDirSize() - 1) //end element of route
18333  {
18334  TPrefDirElement PDE = GetFixedPrefDirElementAt(267, PrefDirVectorStartPosition);
18336 //the above returns a route (or no route) but LinkPos can be entry or exit, and need to know it's the entry link for the follow-on route to be valid
18337  if(RouteType == TAllRoutes::NoRoute)
18338  {
18339  SkipForwardLook = true; //if there's no linked forward route then skip
18340  if(PrefDirVector.back().TrackType == Buffers)
18341  {
18342  Attribute = 1; // treat buffer as red signal
18343  }
18344  if(PrefDirVector.back().TrackType == Continuation)
18345  { //check if timing out and no train between 1st signal and continuation and if so don't change attribute
18346  bool SetAttributeTo3 = true;
18349  {
18350  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
18351  AutoSigVectorIT++)
18352  {
18353  if(!AllRoutes->AllRoutesVector.empty())
18354  {
18355  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
18356  {
18357  SetAttributeTo3 = false;
18358  Attribute = AutoSigVectorIT->AccessNumber;
18359  break;
18360  }
18361  }
18362  }
18363  }
18364  if(SetAttributeTo3)
18365  {
18366  Attribute = 3; // treat continuation as a green signal
18367  }
18368  }
18369  }
18370  else //startpos still on end element and there is probably a forward route
18371  {
18372  TPrefDirElement NewRoutePDE = AllRoutes->GetFixedRouteAt(228, NextForwardLinkedRouteNumber).GetFixedPrefDirElementAt(270, 0); //0 is start position
18373  if(NewRoutePDE.ELinkPos != Track->TrackElementAt(1584, PDE.TrackVectorPosition).ConnLinkPos[PDE.XLinkPos]) //if it's not then route not linked so there's no forward route
18374  {
18375  SkipForwardLook = true; //if there's no linked forward route then skip
18376  if(PrefDirVector.back().TrackType == Buffers)
18377  {
18378  Attribute = 1; // treat buffer as red signal
18379  }
18380  if(PrefDirVector.back().TrackType == Continuation)
18381  {
18382  Attribute = 3; // treat continuation as a green signal
18383  }
18384  }
18385  //else there is a forward route, so just continue to examine it below unless SkipForwardLook is true
18386  }
18387  }
18388 
18389  if(!SkipForwardLook)
18390  {
18391  //start from element in front of PrefDirVectorStartPosition, which may be in same or next forward route (if there isn't one then
18392  //SkipForwardLook will be true - see above)
18393  int StartPos;
18394  if((unsigned int)PrefDirVectorStartPosition < (PrefDirSize() - 1))
18395  {
18396  StartPos = PrefDirVectorStartPosition + 1;
18397  }
18398  else
18399  {
18400  StartPos = 0; //start of next forward route
18401  }
18402  if(StartPos > 0) //starting in this route
18403  {
18404  if(!FindForwardTargetSignalAttribute(2, NextForwardLinkedRouteNumber, Attribute, StartPos))// returns false for having to link to next route to continue search
18405  {
18406  StartPos = 0; //reset to 0 for next route
18407  while(!AllRoutes->GetFixedRouteAt(229, NextForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(3, NextForwardLinkedRouteNumber, Attribute, StartPos))
18408  {
18409  continue;
18410  }
18411  }
18412  }
18413  else //starting in next forward route
18414  {
18415  while(!AllRoutes->GetFixedRouteAt(230, NextForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(4, NextForwardLinkedRouteNumber, Attribute, StartPos))
18416  {
18417  continue;
18418  }
18419  }
18420  }
18421 
18422  //now have target attribute (as supplied or modified in forward look) so look backwards to set signals
18423  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18424  {
18425  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
18426  if(PrefDirPtr->TrackType == Bridge)
18427  {
18428  if(PrefDirPtr->XLinkPos < 2)
18429  {
18430  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18431  }
18432  else
18433  {
18434  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18435  }
18436  }
18437  if(TrainID != -1)
18438  {
18439  Utilities->CallLogPop(334);
18440  return(false);
18441  }
18442  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
18443  // the attribute to 0 so first signal behind the LC is red
18444  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
18445  {
18446  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
18447  {
18448  Attribute = 0;
18449  }
18450  }
18451 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
18452 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
18453  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
18454  {
18455  if((!AllRoutes->RouteBackTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
18456  PrefDirPtr->PrefDirRoute)
18457  {
18458 //new section at v2.9.2 to check for pref dir element in a locked route, and if so set Attribute to 0 (red). When emerge from locked route Attribute
18459 //still 0 so first signal behind it also stays red. After that Attribute goes back to normal.
18460  int LockedVecNum = 0; //not used
18461  TPrefDirElement DummyPrefDir; //not used
18462  bool KeepAttributeAt0ForLockedRoute = false;
18463  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(15, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, DummyPrefDir,
18464  LockedVecNum))
18465  {
18466  Attribute = 0;
18467  KeepAttributeAt0ForLockedRoute = true;
18468  }
18469 //end of v2.9.2 addition
18470 
18471 //v2.14.0 addition to avoid incrementing attribute for forward ground signals, ground sig itself takes attribute of forward signal + 1
18472  bool NotGroundSignal = false;
18473  if(PrefDirPtr->SigAspect != TTrackElement::GroundSignal)
18474  {
18475  NotGroundSignal = true;
18476  }
18477 
18478  if(Track->TrackElementAt(1529, PrefDirPtr->TrackVectorPosition).Failed) //addition at v2.13.0 for signal failures
18479  {
18480  Attribute = 0; //stays at 0
18481  }
18482 
18483  if(Attribute < 3)
18484  {
18485  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
18486  }
18487  else
18488  {
18489  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
18490  }
18491  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
18492  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
18493  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
18494  {
18495  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
18496  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
18497  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
18498  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
18499  }
18500  if((Attribute < 3) && !KeepAttributeAt0ForLockedRoute && (NotGroundSignal || (Attribute == 0))) //NotGroundSignal... added at v2.14.0 (see above)
18501  { //if groundsignal attrib is 0 then do need to increment
18502  Attribute++; //this is for the next signal rearwards, not the current one
18503  }
18504 // Display->Update(); // update after recent plots //dropped at v2.14.0 to avoid signals on routes showing before loaded session, relaced by the below
18505  AllRoutes->RebuildRailwayFlag = true; //added at v2.14.0 to force a rebuild in place of the above
18506  }
18507  }
18508  }
18509  }
18510  Utilities->CallLogPop(335);
18511  return(true);
18512 }
18513 
18514 // ---------------------------------------------------------------------------
18515 
18516 void TOneRoute::TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
18517 /*
18518  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
18519  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
18520  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
18521  Selection invalid if select a bridge; trying to leave a single element; last element to be left
18522  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
18523  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
18524  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
18525  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
18526 */
18527 {
18528  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TruncateRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
18529  "," + AnsiString((short)PrefDirRoute));
18530  bool ElementInRoute = false;
18531  bool MovingTrainOccupyingRoute = false;
18532  unsigned int TruncatePDElementPos; //the selected PD position to truncate to (could be from the back or the front)//added at v2.15.0
18533  enum {NoTruncate, BackTruncate, FrontTruncate, FullTruncate} TruncateType;
18534  TruncateType = NoTruncate;
18536 
18537  for(unsigned int b = 0; b < PrefDirSize(); b++)
18538  {
18539  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
18540  {
18541  TruncatePDElementPos = b;
18542  ElementInRoute = true;
18543  break;
18544  }
18545  }
18546  if(!ElementInRoute)
18547  {
18548  ReturnFlag = NotInRoute;
18549  Utilities->CallLogPop(336);
18550  return;
18551  }
18552 
18553  //now find whether back, front or full truncate //added at v2.15.0
18554  if(TruncatePDElementPos < (PrefDirSize() - 1)) //if last position then can't be a front truncate
18555  {
18556  if(TruncatePDElementPos == 0)
18557  {
18558  TruncateType = FullTruncate;
18559  AllRoutes->RouteBackTruncateFlag = true; //Added at v2.15.1: FullTruncate is also a form of BackTruncate as far as the flag is concerned for SetAllRearwardsSignals
18560  } //without this, if a non-autosigs route is in front of an autosigs route and runs into buffers or a
18561  else //continuation, and the non-autosigs route is truncated back to the autosigs route (i.e. a full
18562  { //truncate for that route), the last signal in the autosigs route doesn't change to red.
18563  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1); //+1 will exist becaue of first condition
18564  if(TempElement.Config[TempElement.XLinkPos] == Signal)
18565  {
18566  TruncateType = FrontTruncate;
18567  }
18568  else
18569  {
18570  TruncateType = BackTruncate;
18572  }
18573  }
18574  }
18575  else // == PrefDirSize() - 1
18576  {
18577  TruncateType = BackTruncate;
18579  }
18580 
18581 // it is in the route so continue, first look for a train or a flashing level crossing in the part to be removed
18582 
18583  if(TruncateType == BackTruncate) //added at v2.15.0
18584  {
18585  for(int b = PrefDirSize() - 1; b >= 0; b--)
18586  {
18587  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
18588  if(PrefDirVector.at(b).TrackType == Bridge)
18589  {
18590  if(PrefDirVector.at(b).XLinkPos < 2)
18591  {
18592  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18593  }
18594  else
18595  {
18596  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18597  }
18598  }
18599  if(TrainID != -1)
18600  {
18601  if(!TrainController->TrainVectorAtIdent(64, TrainID).Stopped())
18602  {
18603  MovingTrainOccupyingRoute = true; // train is behind the truncate point & moving
18604  }
18605  }
18606  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18607  {
18608  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
18609  ReturnFlag = InRouteFalse;
18611  Utilities->CallLogPop(1941);
18612  return;
18613  }
18614  if(b == int(TruncatePDElementPos))
18615  {
18616  break; // OK found truncate element & no flashing LC in front
18617  }
18618  }
18619  }
18620  else if(TruncateType == FrontTruncate)//front/full truncate //added at v2.15.0
18621  {
18622  for(unsigned int b = 0; b < PrefDirSize(); b++) //search forwards
18623  {
18624  int TrainID = Track->TrackElementAt(1577, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
18625  if(PrefDirVector.at(b).TrackType == Bridge)
18626  {
18627  if(PrefDirVector.at(b).XLinkPos < 2)
18628  {
18629  TrainID = Track->TrackElementAt(1557, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18630  }
18631  else
18632  {
18633  TrainID = Track->TrackElementAt(1558, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18634  }
18635  }
18636  if(TrainID != -1)
18637  {
18638  if(!TrainController->TrainVectorAtIdent(65, TrainID).Stopped())
18639  {
18640  MovingTrainOccupyingRoute = true; // train is behind the truncate point & moving
18641  }
18642  }
18643  if(Track->IsLCBarrierFlashingAtHV(4, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18644  {
18645  TrainController->StopTTClockMessage(143, "Can't cancel a route containing a level crossing that is changing state");
18646  ReturnFlag = InRouteFalse;
18648  Utilities->CallLogPop(2571);
18649  return;
18650  }
18651  if(b == TruncatePDElementPos)
18652  {
18653  break; // OK found truncate element & no flashing LC behind
18654  }
18655  }
18656  }
18657  else //FullTruncate) //added at v2.15.0
18658  {
18659  for(unsigned int b = 0; b < PrefDirSize(); b++) //search the entire route forwards
18660  {
18661  int TrainID = Track->TrackElementAt(1559, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
18662  if(PrefDirVector.at(b).TrackType == Bridge)
18663  {
18664  if(PrefDirVector.at(b).XLinkPos < 2)
18665  {
18666  TrainID = Track->TrackElementAt(1560, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18667  }
18668  else
18669  {
18670  TrainID = Track->TrackElementAt(1561, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18671  }
18672  }
18673  if(TrainID != -1)
18674  {
18675  if(!TrainController->TrainVectorAtIdent(66, TrainID).Stopped())
18676  {
18677  MovingTrainOccupyingRoute = true; // train is behind the truncate point & moving
18678  }
18679  }
18680  if(Track->IsLCBarrierFlashingAtHV(5, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18681  {
18682  TrainController->StopTTClockMessage(144, "Can't cancel a route containing a level crossing that is changing state");
18683  ReturnFlag = InRouteFalse;
18685  Utilities->CallLogPop(2572);
18686  return;
18687  }
18688  }
18689  }
18690 
18691  if(PrefDirVector.at(TruncatePDElementPos).TrackType == Bridge)
18692  {
18693  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncation point");
18694  ReturnFlag = InRouteFalse;
18696  Utilities->CallLogPop(338);
18697  return;
18698  }
18699  if(((TruncatePDElementPos == 1) && (TruncateType == BackTruncate)) || ((TruncatePDElementPos == (PrefDirSize() - 2)) && (TruncateType == FrontTruncate)))
18700  {
18701  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
18702  ReturnFlag = InRouteFalse;
18704  Utilities->CallLogPop(339);
18705  return;
18706  }
18707 
18708  if((TruncatePDElementPos > 0) && (TruncateType == BackTruncate))
18709  {
18710  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1);
18711  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
18712  {
18713  if(TempElement.Config[TempElement.XLinkPos] != Signal)
18714  {
18715  TrainController->StopTTClockMessage(145, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
18716  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
18717  "that lies within the route;\n\nor to remove the whole route select the first track element in the route");
18718  ReturnFlag = InRouteFalse;
18720  Utilities->CallLogPop(340);
18721  return;
18722  }
18723  }
18724  else
18725  {
18726  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
18727  {
18728  TrainController->StopTTClockMessage(60, "Can't leave points, bridge or crossover as the last route element");
18729  ReturnFlag = InRouteFalse;
18731  Utilities->CallLogPop(341);
18732  return;
18733  }
18734  }
18735  }
18736 
18737  else if((TruncatePDElementPos < (PrefDirSize() - 1)) && (TruncateType == FrontTruncate))
18738  {
18739  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1);
18740  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
18741  {
18742  if(TempElement.Config[TempElement.XLinkPos] != Signal)
18743  {
18744  TrainController->StopTTClockMessage(146, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
18745  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
18746  "that lies within the route;\n\nor to remove the whole route select the first track element in the route");
18747  ReturnFlag = InRouteFalse;
18749  Utilities->CallLogPop(2573);
18750  return;
18751  }
18752  }
18753  else //red route
18754  {
18755  if(TruncatePDElementPos > 0)
18756  {
18757  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1); //element behind truncation point
18758  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
18759  {
18760  TrainController->StopTTClockMessage(147, "Can't leave points, bridge or crossover as the last route element");
18761  ReturnFlag = InRouteFalse;
18763  Utilities->CallLogPop(2574);
18764  return;
18765  }
18766  }
18767  }
18768  }
18769 
18770  else if(TruncatePDElementPos == 0) //full truncate
18771  {
18772  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos);
18773  if(TempElement.AutoSignals) //PrefDir route ok as can start after a signal that is in a blue route
18774  {
18775  if((TempElement.Config[TempElement.XLinkPos] != Signal) && (TempElement.Config[TempElement.ELinkPos] != End))
18776  {
18777  TrainController->StopTTClockMessage(148, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
18778  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
18779  "that lies within the route;\n\nor to remove the whole route select the first track element in the route");
18780  ReturnFlag = InRouteFalse;
18782  Utilities->CallLogPop(2575);
18783  return;
18784  }
18785  }
18786  else if(TempElement.PrefDirRoute) //red routes always ok for full truncate as can't leave a bridge/crossover/points as last element in route
18787  {
18788  if(TempElement.TrackType == Bridge)
18789  {
18790  TrainController->StopTTClockMessage(149, "Can't select a bridge as a route truncation point"); //should have been caught above but include for completeness
18791  ReturnFlag = InRouteFalse;
18793  Utilities->CallLogPop(2576);
18794  return;
18795  }
18796  }
18797  }
18798 
18799  int ThisRouteNumber;
18801 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
18802 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
18803 
18804 // check if part of this route already locked & disallow if so
18805  if(!(AllRoutes->LockedRouteVector.empty()))
18806  {
18808  {
18809  if(LRVIT->RouteNumber == ThisRouteNumber)
18810  {
18811  TrainController->StopTTClockMessage(61, "Can't truncate a route that contains a locked section");
18812  ReturnFlag = InRouteFalse;
18814  Utilities->CallLogPop(749);
18815  return;
18816  }
18817  }
18818  }
18819 
18820  unsigned int LookBackwardsFromHere = 0; //added at v2.15.0 - covers front & full truncate & search starts here and looks backwards to see if a train
18821  if(TruncateType == BackTruncate) //is within 3 running signals on this or linked rearwards routes -m this is a PDElement position
18822  {
18823  LookBackwardsFromHere = TruncatePDElementPos;
18824  }
18825 
18826 // RouteLockingRequired should be ok with the above mod but need to lock either forwards or backwards
18827  int RearPosition; //these are the PDElement positions for the route section to be removed and/or locked (inclusive)
18828  int FrontPosition;
18829 
18830  if(AllRoutes->RouteLockingRequired(0, ThisRouteNumber, LookBackwardsFromHere) || MovingTrainOccupyingRoute) // added MovingTrainOccupyingRoute at v2.1.0,
18831  // RouteLockingRequired only checks for trains approaching
18832  {
18835  int button = Application->MessageBox(L"Moving train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
18836  L"Warning!", MB_YESNO | MB_ICONWARNING);
18837  TrainController->BaseTime = TDateTime::CurrentDateTime();
18839  if(button == IDNO)
18840  {
18841  ReturnFlag = InRouteTrue; // still return true even though don't act on it
18843  Utilities->CallLogPop(342);
18844  return;
18845  }
18846  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition).ElementID);
18847  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
18848  TAllRoutes::TLockedRouteClass LockedRoute;
18849  bool ExistingLockedRouteModified = false;
18850  LockedRoute.RouteNumber = ThisRouteNumber;
18851  if(TruncateType == BackTruncate)
18852  {
18853  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
18854  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
18855  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
18856  }
18857  else if(TruncateType == FrontTruncate)
18858  {
18859  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
18860  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
18861  LockedRoute.LastXLinkPos = PrefDirVector.at(TruncatePDElementPos).XLinkPos;
18862  }
18863  else //FullTruncate
18864  {
18865  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
18866  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
18867  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
18868  }
18869 
18870  LockedRoute.LockStartTime = TrainController->TTClockTime;
18871 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
18872 // to use the new RearTrackVectorPosition & LockStartTime (shouldn't as should have been rejected earlier if part-locked, but leave in)
18873  if(!AllRoutes->LockedRouteVector.empty())
18874  {
18875  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
18876  LRVIT++)
18877  {
18878  if(LRVIT->RouteNumber == ThisRouteNumber)
18879  {
18880  LRVIT->RearTrackVectorPosition = LockedRoute.RearTrackVectorPosition;
18881  LRVIT->LockStartTime = LockedRoute.LockStartTime;
18882  ExistingLockedRouteModified = true;
18883  }
18884  }
18885  }
18886  if(!ExistingLockedRouteModified)
18887  {
18888  AllRoutes->LockedRouteVector.push_back(LockedRoute);
18889  }
18890  if(TruncateType == BackTruncate)
18891  {
18892  AllRoutes->SetAllRearwardsSignals(2, 0, ThisRouteNumber, TruncatePDElementPos);
18893  RearPosition = TruncatePDElementPos;
18894  FrontPosition = PrefDirSize() - 1;
18895  }
18896  else if(TruncateType == FrontTruncate)
18897  {
18898  AllRoutes->SetAllRearwardsSignals(13, 0, ThisRouteNumber, 0);
18899  RearPosition = 0;
18900  FrontPosition = TruncatePDElementPos;
18901  }
18902  else //FullTruncate
18903  {
18904  AllRoutes->SetAllRearwardsSignals(14, 0, ThisRouteNumber, 0);
18905  RearPosition = 0;
18906  FrontPosition = PrefDirSize() - 1;
18907  }
18908 // for(int c = PrefDirSize() - 1; c >= (int)TruncatePDElementPos; c--) // must use int for >= test to succeed when b == 0
18909  for(int c = FrontPosition; c >= RearPosition; c--)
18910  {
18911  // return all signals to red in route section to be truncated
18912  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, ThisRouteNumber).PrefDirVector.at(c);
18913  TTrackElement& TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
18914  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
18915  {
18916  TrackElement.Attribute = 0;
18917  Track->PlotSignal(2, TrackElement, Display);
18918  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
18919  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
18920  }
18921  }
18922 // Display->Update();//not needed as Clearand... called on return from SearchAllRoutesAndTruncate in InterfaceUnit
18923  ReturnFlag = InRouteTrue;
18924  }
18925  else //route locking not required
18926  {
18927  if(TruncateType == BackTruncate)
18928  {
18929  RearPosition = TruncatePDElementPos;
18930  FrontPosition = PrefDirSize() - 1;
18931  AllRoutes->SetAllRearwardsSignals(21, 0, ThisRouteNumber, TruncatePDElementPos);
18932  }
18933  else if(TruncateType == FrontTruncate)
18934  {
18935  RearPosition = 0;
18936  FrontPosition = TruncatePDElementPos;
18937  AllRoutes->SetAllRearwardsSignals(15, 0, ThisRouteNumber, 0);
18938  }
18939  else
18940  {
18941  RearPosition = 0;
18942  FrontPosition = PrefDirSize() - 1;
18943  AllRoutes->SetAllRearwardsSignals(16, 0, ThisRouteNumber, 0);
18944  }
18945 
18946  //now (before truncate route) store the front and rear PrefDir elements of the route for later adaptation (will only be used for blue routes)
18947  //into adjacent red or green routes if there are any (after the truncation/removal)
18948 
18949  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(260, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
18950  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(261, 0);
18951 // bool AddRedAtEnd = false, AddRedAtStart = false, AddGreenAtEnd = false, AddGreenAtStart = false;
18952 
18953  for(int c = FrontPosition; c >= RearPosition; c--) //truncate or remove the route
18954  {
18955  AllRoutes->RemoveRouteElement(5, PrefDirVector.at(c).HLoc, PrefDirVector.at(c).VLoc, PrefDirVector.at(c).ELink);
18956  ReturnFlag = InRouteTrue;
18957  }
18958 
18959  if(LastPDElement.AutoSignals)
18960  {
18961  ReclaimSignalsForNonAutoSigRoutes(0, LastPDElement, FirstPDElement);
18962  }
18963  }
18964 
18965  AllRoutes->CheckMapAndRoutes(5); // test
18966  ReturnFlag = InRouteTrue;
18968  Utilities->CallLogPop(344);
18969 }
18970 
18971 // ---------------------------------------------------------------------------
18972 
18974 {
18975 /*
18976 Need to ensure that green routes always end on a signal (or continuation, but continuations aren't relevant for these purposes) as they can't be extended from other than a
18977 signal.
18978 For green/red routes, a new route that is created FROM a signal - that signal stays in the original route that ended there,
18979  but a new route that is created TO a signal - that signal becomes part of the new route.
18980 For blue routes, a new route created FROM and/or TO a signal - that signal becomes part of the blue route.
18981 So, truncating a blue route from the front leaves a green/red route ending short of the signal - add green/red signal to route at end of route
18982  truncating a blue route from the back leaves a green/red route starting behind the signal - add green/red signal to route at start of route
18983  truncating a red route from the front (in advance of a facing red route signal) ok as the signal is still in the (single element) red route and still allows trains to pass
18984  truncating a red route from the back (anywhere in the red route except as above) ok as at worst (and done deliberately) the red route stops short of a signal but can be extended to it
18985  truncating a green route from the front (in advance of a facing green route signal) ok as the signal is still in the (single element) green route and still allows trains to pass
18986  truncating a green route from the back (in rear of a green route signal) ok as signal still in green route
18987 */
18988 
18989  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ", LastPDElement TrackID " +
18990  Track->TrackElementAt(1562, LastPDElement.TrackVectorPosition).ElementID + ", FirstPDElement TrackID " +
18991  Track->TrackElementAt(1563, FirstPDElement.TrackVectorPosition).ElementID);
18992  if(!LastPDElement.AutoSignals) //shouldn't be called other than for a blue route
18993  {
18994  Utilities->CallLogPop(2578);
18995  return;
18996  }
18997  TPrefDirElement NewGreenFirstPDElement, NewRedFirstPDElement, NewGreenLastPDElement, NewRedLastPDElement;
18998  int RouteColour;
18999  //check if there's a linked forward route missing a signal and if so add it (will only apply for blue routes)
19000  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
19001  {
19002  TPrefDirElement FirstForwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(0);
19003  if(FirstForwardLinkedPDElement.Conn[FirstForwardLinkedPDElement.ELinkPos] == LastPDElement.TrackVectorPosition)
19004  { //found a linked forward route
19005  //check if signal behind this route has been removed from the blue route
19006  if(!AllRoutes->TrackIsInARoute(19, LastPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
19007  { //signal needs to be added at start of this linked route
19008 
19009  RouteColour = FirstForwardLinkedPDElement.GetRouteColour(FirstForwardLinkedPDElement.EXGraphicPtr);
19010  if(RouteColour == 1) //red route
19011  {
19012  NewRedFirstPDElement = LastPDElement;
19013  NewRedFirstPDElement.AutoSignals = false;
19014  NewRedFirstPDElement.PrefDirRoute = false;
19015  NewRedFirstPDElement.EXGraphicPtr = NewRedFirstPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
19016  NewRedFirstPDElement.IsARoute = true;
19017  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(31, x);
19018  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewRedFirstPDElement); //insert at front
19019  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
19020  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
19021  {
19022  if(R2MMIt->second.first == int(x))
19023  {
19024  R2MMIt->second.second++;
19025  }
19026  }
19027  AllRoutes->Route2MultiMapInsert(1, NewRedFirstPDElement.HLoc, NewRedFirstPDElement.VLoc, NewRedFirstPDElement.ELink, x, 0); //0 is new first element number
19028  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
19029  AllRoutes->SetAllRearwardsSignals(17, 0, x, AllRoutes->GetFixedRouteAt(225, x).PrefDirVector.size() - 1); //should be red but make sure
19030  }
19031  else if(RouteColour == 2) //green route
19032  {
19033  NewGreenFirstPDElement = LastPDElement;
19034  NewGreenFirstPDElement.AutoSignals = false;
19035  NewGreenFirstPDElement.PrefDirRoute = true;
19036  NewGreenFirstPDElement.EXGraphicPtr = NewGreenFirstPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
19037  NewGreenFirstPDElement.IsARoute = true;
19038  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(32, x);
19039  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewGreenFirstPDElement); //insert at front
19040  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
19041  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
19042  {
19043  if(R2MMIt->second.first == int(x))
19044  {
19045  R2MMIt->second.second++;
19046  }
19047  }
19048  AllRoutes->Route2MultiMapInsert(2, NewGreenFirstPDElement.HLoc, NewGreenFirstPDElement.VLoc, NewGreenFirstPDElement.ELink, x, 0); //0 is new first element number
19049  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
19050  AllRoutes->SetAllRearwardsSignals(18, 0, x, AllRoutes->GetFixedRouteAt(226, x).PrefDirVector.size() - 1); //should be red but make sure
19051  }
19052  }
19053  break; //no point looking any further
19054  }
19055  }
19056 
19057 //check if there's a linked rearward route missing a signal and if so add it
19058  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
19059  {
19060  TPrefDirElement LastRearwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(AllRoutes->AllRoutesVector.at(x).PrefDirVector.size() - 1);
19061  if(LastRearwardLinkedPDElement.Conn[LastRearwardLinkedPDElement.XLinkPos] == FirstPDElement.TrackVectorPosition)
19062  { //found a linked rearward route
19063  //check if signal in front of this route has been removed from the blue route
19064  if(!AllRoutes->TrackIsInARoute(20, FirstPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
19065  { //signal needs to be added at end of this linked route
19066 
19067  RouteColour = LastRearwardLinkedPDElement.GetRouteColour(LastRearwardLinkedPDElement.EXGraphicPtr);
19068  if(RouteColour == 1) //red route
19069  {
19070  NewRedLastPDElement = FirstPDElement;
19071  NewRedLastPDElement.AutoSignals = false;
19072  NewRedLastPDElement.PrefDirRoute = false;
19073  NewRedLastPDElement.EXGraphicPtr = NewRedLastPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
19074  AllRoutes->AddRouteElement(4, NewRedLastPDElement.HLoc, NewRedLastPDElement.VLoc, NewRedLastPDElement.ELink, x, NewRedLastPDElement);
19075  //can use this as adding to the end of the route
19076  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
19077  AllRoutes->SetAllRearwardsSignals(19, 0, x, AllRoutes->GetFixedRouteAt(223, x).PrefDirVector.size() - 1); //should be red but make sure
19078  }
19079  else if(RouteColour == 2) //green route
19080  {
19081  NewGreenLastPDElement = FirstPDElement;
19082  NewGreenLastPDElement.AutoSignals = false;
19083  NewGreenLastPDElement.PrefDirRoute = true;
19084  NewGreenLastPDElement.EXGraphicPtr = NewGreenLastPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
19085  AllRoutes->AddRouteElement(5, NewGreenLastPDElement.HLoc, NewGreenLastPDElement.VLoc, NewGreenLastPDElement.ELink, x, NewGreenLastPDElement);
19086  //can use this as adding to the end of the route
19087  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
19088  AllRoutes->SetAllRearwardsSignals(20, 0, x, AllRoutes->GetFixedRouteAt(224, x).PrefDirVector.size() - 1); //should be red but make sure
19089  }
19090  }
19091  break; //no point looking any further
19092  }
19093  }
19094  Utilities->CallLogPop(2579);
19095 }
19096 
19097 // ---------------------------------------------------------------------------
19098 
19100 /*
19101  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
19102  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
19103  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
19104  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
19105  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
19106  the route colours.
19107 */
19108 {
19109  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
19110  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
19112  int RouteNumber;
19113  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
19114  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
19115  //these added at v2.15.0
19116  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(263, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
19117  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(264, 0);
19118 
19119  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
19120  {
19121  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
19122  {
19123  if(PrefDirVector.at(x).TrackType == SignalPost)
19124  {
19125  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
19126  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
19127  }
19128  }
19129 // AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0); //dropped at v2.17.0 in favour of setting all signals after route removal (see below)
19130  //Fault found on B'ham when train (2A09) exited from Snow Hill terminal platform (no signal) when orce cancelled
19131  //route above, but when rearwards signals set the route to be cancelled still exists, so setting signals first uses
19132  //forward look when it finds a red signal in the route to be cancelled, so first signal in rear route becames yellow
19133  //when should have been be red.
19134 // already set all signals to red in route so start at start of route for further rearwards signal setting <- comment invalid after above
19135  }
19136  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
19137  {
19138  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
19139  }
19140 
19141  if(LastPDElement.AutoSignals) //added at v2.15.0
19142  {
19143  ReclaimSignalsForNonAutoSigRoutes(1, LastPDElement, FirstPDElement);
19144  }
19145 
19146  if(AllRoutes->AllRoutesVector.size() > 0) //added at v2.17.0 - see above
19147  {
19148  for(TAllRoutes::TAllRoutesVectorIterator ARVIt = AllRoutes->AllRoutesVector.begin(); ARVIt < AllRoutes->AllRoutesVector.end(); ARVIt++)
19149  {
19150  ARVIt->SetRouteSignals(14);
19151  }
19152  }
19153  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
19154  AllRoutes->CheckMapAndRoutes(9); // test
19155  TrainController->BaseTime = TDateTime::CurrentDateTime();
19157  Utilities->CallLogPop(345);
19158  return;
19159 }
19160 
19161 // ---------------------------------------------------------------------------
19162 
19163 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
19164 /*
19165  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
19166 */
19167 {
19168  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
19169  AnsiString((short)PrefDirRoute));
19170  if(SearchVector.empty())
19171  {
19172  Utilities->CallLogPop(1149);
19173  return;
19174  }
19175  for(unsigned int b = 0; b < SearchVector.size(); b++)
19176  {
19179  PrefDirRoute);
19180  }
19181  Utilities->CallLogPop(346);
19182 }
19183 
19184 // ---------------------------------------------------------------------------
19185 
19186 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
19187 /*
19188  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
19189  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
19190  TOneRoute.
19191 */
19192 {
19193  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteFlashValues," + AnsiString((short)AutoSigsFlag) + "," +
19194  AnsiString((short)PrefDirRoute));
19195  RouteFlash.RouteFlashVector.clear();
19196  TRouteFlashElement RouteFlashElement;
19197 
19198  for(unsigned int b = 0; b < SearchVector.size(); b++)
19199  {
19200  int H = GetFixedSearchElementAt(11, b).HLoc;
19201  int V = GetFixedSearchElementAt(12, b).VLoc;
19203  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
19204  RouteFlashElement.HLoc = H;
19205  RouteFlashElement.VLoc = V;
19207  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
19208  }
19209  Utilities->CallLogPop(348);
19210 }
19211 
19212 // ---------------------------------------------------------------------------
19213 
19214 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
19215 {
19216  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
19217  if(!PrefDirVector.empty())
19218  {
19219  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
19220  {
19221  int H = PrefDirPtr->HLoc;
19222  int V = PrefDirPtr->VLoc;
19223  // check for any LCs that are closed to trains & set the flash values and store in the vector
19224  if(Track->IsLCAtHV(39, H, V))
19225  {
19226  if(Track->IsLCBarrierUpAtHV(0, H, V))
19227  {
19228  Track->LCChangeFlag = true;
19229  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
19230  CLC.HLoc = H;
19231  CLC.VLoc = V;
19233  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
19236  if(PrefDirRoute)
19237  {
19238  CLC.TypeOfRoute = 1;
19239  }
19240  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
19241  Track->ChangingLCVector.push_back(CLC);
19242  }
19243  }
19244  }
19245  }
19246  Utilities->CallLogPop(1948);
19247 }
19248 
19249 // ---------------------------------------------------------------------------
19250 
19252 /*
19253  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
19254  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
19255  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
19256  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
19257 */
19258 {
19259  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
19260  if(!OverlayPlotted)
19261  {
19262  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
19263  {
19264  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
19265  {
19266  continue;
19267  }
19268  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
19269  Display->Update();
19270  }
19271  OverlayPlotted = true;
19272  }
19273  Utilities->CallLogPop(349);
19274 }
19275 
19276 // ---------------------------------------------------------------------------
19277 
19279 /*
19280  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
19281  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
19282  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
19283  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
19284 */
19285 {
19286  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
19287  if(OverlayPlotted)
19288  {
19289  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
19290  {
19291  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
19292  {
19293  continue;
19294  }
19295  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
19296  Display->Update();
19297  }
19298  OverlayPlotted = false;
19299  }
19300  Utilities->CallLogPop(350);
19301 }
19302 
19303 // ---------------------------------------------------------------------------
19304 
19305 bool TOneRoute::SignalHasFailed(int Caller) //added at v2.13.0
19306 {
19307 /*enter with SearchVector fully populated & with a legitimate route found, return true for failure.
19308 Look along SearchVector backwards, skip first signal found (i.e. last in route), but for all others
19309 including first signal in route offer chance to fail (since they all change aspect), but if find any failed point
19310 where no route available (i.e. a dead end, points checked after search in PointsToBeChanged) then return false - i.e. don't
19311 allow signal failure in an unviable route. If fail (i.e. prior to returning true), alter graphic, send
19312 messages, and allocate a repair time similar to points)
19313 */
19314 
19315  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SignalHasFailed");
19316  if((Utilities->FailureMode == FNil) || (SearchVector.size() < 2)) //added (SearchVector.size() < 2) at v2.14.0 as rely on it being at least 2 below
19317  {
19318  Utilities->CallLogPop(2528);
19319  return(false);
19320  }
19321  bool FirstSignalFound = false;
19322  for(TPrefDirVector::iterator PDVIt = SearchVector.end() - 1; PDVIt >= SearchVector.begin(); PDVIt--)
19323  {
19324  TTrackElement &TE = Track->TrackElementAt(1530, PDVIt->TrackVectorPosition);
19325 //check for a failed point where needs to change to make the route
19326 //shouldn't be any but check to be safe
19327  int Attr = TE.Attribute;
19328  if(PDVIt->TrackType == Points)
19329  {
19330  if((PDVIt->ELinkPos == 1) || (PDVIt->XLinkPos == 1)) // 1=want to go straight
19331  {
19332  if(Attr == 1) //currently set to diverge
19333  {
19334  if(TE.Failed)
19335  {
19336  Utilities->CallLogPop(2529);
19337  return(false); //return without further checking
19338  }
19339  }
19340  }
19341  else if((PDVIt->ELinkPos == 3) || (PDVIt->XLinkPos == 3)) // 3=want to diverge
19342  {
19343  if(Attr == 0) //currently set to go straight
19344  {
19345  if(TE.Failed)
19346  {
19347  Utilities->CallLogPop(2530);
19348  return(false); //return without further checking
19349  }
19350  }
19351  }
19352  }
19353  //now need to check if PDVIt->XLinkPos is set (> -1) as if an unrestricted route and start on a signal not in an existing route then XLinkPos won't be set
19354  //changed at v2.14.0 to ensure both prefdir & unrestricted routes can have first signal fail (by determining what XLinkPos should be and using it, but not changing
19355  //the search vector)
19356  int XLinkPosition = PDVIt->XLinkPos;
19357  if(PDVIt->XLinkPos == -1)
19358  {
19359  if(PDVIt < (SearchVector.end() - 1)) //no good if end element as need to examine the later one, though shouldn't have XLinkPos unset if so
19360  {
19361  for(int x = 0; x < 4; x++)
19362  {
19363  if(PDVIt->Conn[x] == (PDVIt + 1)->TrackVectorPosition)
19364  {
19365  XLinkPosition = x;
19366  break;
19367  }
19368  }
19369  }
19370  else
19371  {
19372  Utilities->CallLogPop(2549);
19373  return(false); //no point going any further
19374  }
19375  }
19376  if(XLinkPosition > -1) //should be by now but be safe
19377  {
19378  if(!FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
19379  {
19380  FirstSignalFound = true; //the first signal doesn't change aspect
19381  continue;
19382  }
19383  else if(FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
19384  {
19385 /*
19386  if(TE.SigAspect == TTrackElement::GroundSignal) //dropped at v2.14.0 to allow ground signals to fail
19387  {
19388  continue; //ground signals don't fail
19389  }
19390 */
19391  if((random(Utilities->SignalChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice
19392  {
19394  IFE.TVPos = PDVIt->TrackVectorPosition;
19395  TE.Failed = true;
19396  TE.Attribute = 0; //stop aspect
19397  Display->WarningLog(22, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal failed at " + TE.ElementID);
19398  PerfLogForm->PerformanceLog(45, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Signal failed at " + TE.ElementID);
19399  TrainController->StopTTClockMessage(132, "Signal at " + TE.ElementID +
19400  " failed when changing aspect.\nTrains can only pass under signaller control.");
19401  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
19402  //set repair time, random value in minutes between 10 and 179
19403  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
19404  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
19405  IFE.RepairTime = RepairTime;
19407  Track->FailedSignalsVector.push_back(IFE);
19409  int RouteNumber; //not used
19410  if(AllRoutes->GetRouteTypeAndNumber(41, IFE.TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
19411  { // 0 for LinkPos ok as a signal so only one track
19412  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(12);
19413  }
19414  Utilities->CallLogPop(2535);
19415  return(true); //return so only allow one failure per route
19416  }
19417  }
19418  }
19419  }
19420  Utilities->CallLogPop(2531);
19421  return(false);
19422 }
19423 
19424 // ---------------------------------------------------------------------------
19425 // ---------------------------------------------------------------------------
19426 
19427 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
19428 {
19429  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
19430  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
19431  {
19432  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
19433  }
19434  Utilities->CallLogPop(120);
19435  return(AllRoutesVector.at(At));
19436 }
19437 
19438 // ---------------------------------------------------------------------------
19439 
19441 {
19442  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
19443  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
19444  {
19445  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
19446  }
19447  Utilities->CallLogPop(121);
19448  return(AllRoutesVector.at(At));
19449 }
19450 
19451 // ---------------------------------------------------------------------------
19452 
19453 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
19454 /*
19455  Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
19456 */
19457 {
19458  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
19459  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19460  {
19461  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
19462  }
19463  Utilities->CallLogPop(351);
19464 }
19465 
19466 // ---------------------------------------------------------------------------
19467 
19468 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
19469 {
19470  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
19471  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19472  {
19473  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
19474  }
19475  Utilities->CallLogPop(1706);
19476 }
19477 
19478 // ---------------------------------------------------------------------------
19479 
19480 bool TAllRoutes::SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
19481 /*
19482  Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in
19483  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
19484  Messages are given in TruncateRoute. If successful the route is truncated at and including
19485  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
19486  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
19487  length (train length).
19488 */
19489 {
19490  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchAllRoutesAndTruncate," + AnsiString(HLoc) + "," +
19491  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
19492  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19493  {
19494  TTruncateReturnType ReturnFlag;
19495 // used in SetRearwardsSignalsReturnFalseForTrainInRear (called by TruncateRoute) to skip continuation & buffer attribute change
19496  GetModifiableRouteAt(7, a).TruncateRoute(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
19497  if(ReturnFlag == NotInRoute)
19498  {
19499  continue;
19500  }
19501  else if(ReturnFlag == InRouteTrue)
19502  {
19503  Utilities->CallLogPop(352);
19504  return(true);
19505  }
19506  else if(ReturnFlag == InRouteFalse)
19507  {
19508  Utilities->CallLogPop(353);
19509  return(false);
19510  }
19511  }
19512  Utilities->CallLogPop(354);
19513  return(false);
19514 }
19515 
19516 // ---------------------------------------------------------------------------
19517 
19518 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
19519 /*
19520  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
19521  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
19522 */
19523 {
19524  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
19525  AnsiString(LinkPos));
19526  if(TrackVectorPosition == -1) // allows for continuation entries & exits
19527  {
19528  Utilities->CallLogPop(355);
19529  return(false);
19530  }
19531  THVPair Route2MultiMapKeyPair;
19532 
19533  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
19534  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
19535  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
19536  TRoute2MultiMapIterator Route2MultiMapIterator;
19537 
19538  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
19539  {
19540  Utilities->CallLogPop(356);
19541  return(false);
19542  }
19543  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
19544  {
19545  Utilities->CallLogPop(1422);
19546  return(true);
19547  }
19548  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1) //remainder for a bridge element
19549  {
19550  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19551 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19552 // realised after writing this that can't be points as would have been covered above, but leave anyway
19553  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
19554  Route2MultiMapIterator->second.second);
19555  EntryLinkPos = PrefDirElement1.ELinkPos;
19556  ExitLinkPos = PrefDirElement1.XLinkPos;
19557  EntryLink = PrefDirElement1.Link[EntryLinkPos];
19558  ExitLink = PrefDirElement1.Link[ExitLinkPos];
19559  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
19560  {
19561  Utilities->CallLogPop(357);
19562  return(true);
19563  }
19564  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
19565  {
19566  Utilities->CallLogPop(358);
19567  return(true);
19568  }
19569  }
19570  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
19571  {
19572  Utilities->CallLogPop(1423);
19573  return(true);
19574  }
19575  Utilities->CallLogPop(363);
19576  return(false); // none found
19577 }
19578 
19579 // ---------------------------------------------------------------------------
19580 
19581 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
19582  Graphics::TBitmap* &EntryDirectionGraphicPtr)
19583 /*
19584  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
19585  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
19586  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
19587  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
19588  for replotting of AutoSigsRoutes.
19589 */
19590 {
19591  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
19592  AnsiString(LinkPos));
19593  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
19594  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
19595  if(TrackVectorPosition == -1)
19596  {
19597  Utilities->CallLogPop(364);
19598  return(NoRoute); // allows for continuation entries & exits
19599  }
19600  THVPair Route2MultiMapKeyPair;
19601 
19602  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
19603  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
19604  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
19605  TRoute2MultiMapIterator Route2MultiMapIterator;
19606 
19607  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
19608  {
19609  Utilities->CallLogPop(365);
19610  return(NoRoute); // none found
19611  }
19612  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
19613  {
19614  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19615 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19616  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
19617  Route2MultiMapIterator->second.second);
19618  EntryLinkPos = PrefDirElement1.ELinkPos;
19619  ExitLinkPos = PrefDirElement1.XLinkPos;
19620  EntryLink = PrefDirElement1.Link[EntryLinkPos];
19621  ExitLink = PrefDirElement1.Link[ExitLinkPos];
19622  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
19623  {
19624  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
19625  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
19626  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
19627  {
19628  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
19629  }
19630  if(PrefDirElement1.AutoSignals)
19631  {
19632  Utilities->CallLogPop(366);
19633  return(AutoSigsRoute);
19634  }
19635  else
19636  {
19637  Utilities->CallLogPop(367);
19638  return(NotAutoSigsRoute);
19639  }
19640  }
19641  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
19642  {
19643  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
19644  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
19645  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
19646  {
19647  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
19648  }
19649  if(PrefDirElement1.AutoSignals)
19650  {
19651  Utilities->CallLogPop(368);
19652  return(AutoSigsRoute);
19653  }
19654  else
19655  {
19656  Utilities->CallLogPop(369);
19657  return(NotAutoSigsRoute);
19658  }
19659  }
19660  }
19661  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
19662  {
19663  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
19664  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19665 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19666  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
19667  EntryLinkPos = PrefDirElement2.ELinkPos;
19668  ExitLinkPos = PrefDirElement2.XLinkPos;
19669  EntryLink = PrefDirElement2.Link[EntryLinkPos];
19670  ExitLink = PrefDirElement2.Link[ExitLinkPos];
19671  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
19672  {
19673  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
19674  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
19675  {
19676  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
19677  }
19678  if(PrefDirElement2.AutoSignals)
19679  {
19680  Utilities->CallLogPop(370);
19681  return(AutoSigsRoute);
19682  }
19683  else
19684  {
19685  Utilities->CallLogPop(371);
19686  return(NotAutoSigsRoute);
19687  }
19688  }
19689  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
19690  {
19691  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
19692  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
19693  {
19694  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
19695  }
19696  if(PrefDirElement2.AutoSignals)
19697  {
19698  Utilities->CallLogPop(372);
19699  return(AutoSigsRoute);
19700  }
19701  else
19702  {
19703  Utilities->CallLogPop(373);
19704  return(NotAutoSigsRoute);
19705  }
19706  }
19707  ItPair.second--; // the second iterator points one past the last matching value
19708  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
19709  EntryLinkPos = PrefDirElement3.ELinkPos;
19710  ExitLinkPos = PrefDirElement3.XLinkPos;
19711  EntryLink = PrefDirElement3.Link[EntryLinkPos];
19712  ExitLink = PrefDirElement3.Link[ExitLinkPos];
19713  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
19714  {
19715  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
19716  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
19717  {
19718  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
19719  }
19720  if(PrefDirElement3.AutoSignals)
19721  {
19722  Utilities->CallLogPop(374);
19723  return(AutoSigsRoute);
19724  }
19725  else
19726  {
19727  Utilities->CallLogPop(375);
19728  return(NotAutoSigsRoute);
19729  }
19730  }
19731  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
19732  {
19733  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
19734  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
19735  {
19736  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
19737  }
19738  if(PrefDirElement3.AutoSignals)
19739  {
19740  Utilities->CallLogPop(376);
19741  return(AutoSigsRoute);
19742  }
19743  else
19744  {
19745  Utilities->CallLogPop(377);
19746  return(NotAutoSigsRoute);
19747  }
19748  }
19749  }
19750  Utilities->CallLogPop(378);
19751  return(NoRoute); // none found
19752 }
19753 
19754 // ---------------------------------------------------------------------------
19755 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
19756 /*
19757  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
19758  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
19759 */
19760 {
19761  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
19762  AnsiString(LinkPos));
19763  if(TrackVectorPosition == -1)
19764  {
19765  RouteNumber = -1;
19766  Utilities->CallLogPop(379);
19767  return(NoRoute); // allows for continuation & buffer entries & exits
19768  }
19769  THVPair Route2MultiMapKeyPair;
19770 
19771  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
19772  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
19773  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
19774  TRoute2MultiMapIterator Route2MultiMapIterator;
19775 
19776  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
19777  {
19778  RouteNumber = -1;
19779  Utilities->CallLogPop(380);
19780  return(NoRoute); // none found
19781  }
19782  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
19783  {
19784  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19785 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19786  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
19787  Route2MultiMapIterator->second.second);
19788  EntryLinkPos = PrefDirElement1.ELinkPos;
19789  ExitLinkPos = PrefDirElement1.XLinkPos;
19790  EntryLink = PrefDirElement1.Link[EntryLinkPos];
19791  ExitLink = PrefDirElement1.Link[ExitLinkPos];
19792  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
19793  {
19794  RouteNumber = Route2MultiMapIterator->second.first;
19795  if(PrefDirElement1.AutoSignals)
19796  {
19797  Utilities->CallLogPop(381);
19798  return(AutoSigsRoute);
19799  }
19800  else
19801  {
19802  Utilities->CallLogPop(382);
19803  return(NotAutoSigsRoute);
19804  }
19805  }
19806  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
19807  {
19808  RouteNumber = Route2MultiMapIterator->second.first;
19809  if(PrefDirElement1.AutoSignals)
19810  {
19811  Utilities->CallLogPop(383);
19812  return(AutoSigsRoute);
19813  }
19814  else
19815  {
19816  Utilities->CallLogPop(384);
19817  return(NotAutoSigsRoute);
19818  }
19819  }
19820  }
19821  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
19822  {
19823  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
19824  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19825 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19826  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
19827  EntryLinkPos = PrefDirElement2.ELinkPos;
19828  ExitLinkPos = PrefDirElement2.XLinkPos;
19829  EntryLink = PrefDirElement2.Link[EntryLinkPos];
19830  ExitLink = PrefDirElement2.Link[ExitLinkPos];
19831  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
19832  {
19833  RouteNumber = ItPair.first->second.first;
19834  if(PrefDirElement2.AutoSignals)
19835  {
19836  Utilities->CallLogPop(385);
19837  return(AutoSigsRoute);
19838  }
19839  else
19840  {
19841  Utilities->CallLogPop(386);
19842  return(NotAutoSigsRoute);
19843  }
19844  }
19845  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
19846  {
19847  RouteNumber = ItPair.first->second.first;
19848  if(PrefDirElement2.AutoSignals)
19849  {
19850  Utilities->CallLogPop(387);
19851  return(AutoSigsRoute);
19852  }
19853  else
19854  {
19855  Utilities->CallLogPop(388);
19856  return(NotAutoSigsRoute);
19857  }
19858  }
19859  ItPair.second--; // the second iterator points one past the last matching value
19860  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
19861  EntryLinkPos = PrefDirElement3.ELinkPos;
19862  ExitLinkPos = PrefDirElement3.XLinkPos;
19863  EntryLink = PrefDirElement3.Link[EntryLinkPos];
19864  ExitLink = PrefDirElement3.Link[ExitLinkPos];
19865  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
19866  {
19867  RouteNumber = ItPair.second->second.first;
19868  if(PrefDirElement3.AutoSignals)
19869  {
19870  Utilities->CallLogPop(389);
19871  return(AutoSigsRoute);
19872  }
19873  else
19874  {
19875  Utilities->CallLogPop(390);
19876  return(NotAutoSigsRoute);
19877  }
19878  }
19879  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
19880  {
19881  RouteNumber = ItPair.second->second.first;
19882  if(PrefDirElement3.AutoSignals)
19883  {
19884  Utilities->CallLogPop(391);
19885  return(AutoSigsRoute);
19886  }
19887  else
19888  {
19889  Utilities->CallLogPop(392);
19890  return(NotAutoSigsRoute);
19891  }
19892  }
19893  }
19894  RouteNumber = -1;
19895  Utilities->CallLogPop(393);
19896  return(NoRoute); // none found
19897 }
19898 
19899 // ---------------------------------------------------------------------------
19900 
19901 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
19902 /*
19903  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
19904  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
19905  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
19906  and Route2MultiMap.
19907 */
19908 {
19909  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
19910  TOneRoute EmptyRoute;
19911 
19912  EmptyRoute.RouteID = NextRouteID;
19913  NextRouteID++;
19914 
19915  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
19916  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
19917  {
19918  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
19919  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
19920  }
19921  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
19922  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
19923 
19924  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
19925  Utilities->CallLogPop(394);
19926 }
19927 
19928 // ---------------------------------------------------------------------------
19929 
19931 /*
19932  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
19933  that is already in Route is used.
19934 */
19935 {
19936  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
19937  TOneRoute EmptyRoute;
19938 
19939  EmptyRoute.RouteID = Route->RouteID;
19940 
19941  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
19942  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
19943  {
19944  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
19945  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
19946  }
19947  Utilities->CallLogPop(1579);
19948 }
19949 
19950 // ---------------------------------------------------------------------------
19951 
19952 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
19953 /*
19954  When attaching a new route section to an existing route, it is sometimes necessary to erase the
19955  original route and create a new composite route. This function Erases all elements in the route
19956  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
19957  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
19958  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
19959  that are greater than the route number that is removed. The LockedRouteVector as also searched
19960  and if any relate to the route that has been cleared they are erased too, but the fact that one
19961  has been found is recorded so that it can be re-established later.
19962 */
19963 {
19964  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
19965  THVPair Route2MultiMapKeyPair;
19966  TRoute2MultiMapEntry Route2MultiMapEntry;
19967  TRoute2MultiMapIterator Route2MultiMapIterator;
19968 
19969 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
19970 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
19971 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
19972 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
19973 // If so the locked route is removed from the locked vector and is lost.
19974  LockedRouteRearTrackVectorPosition = 0;
19975  LockedRouteLastTrackVectorPosition = 0;
19976  LockedRouteLastXLinkPos = 0;
19977  LockedRouteLockStartTime = TDateTime(0);
19978  if(!LockedRouteVector.empty())
19979  {
19980  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
19981  {
19982  if(LRVIT->RouteNumber == RouteNumber)
19983  {
19984  LockedRouteRearTrackVectorPosition = LRVIT->RearTrackVectorPosition;
19985  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
19986  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
19987  LockedRouteLockStartTime = LRVIT->LockStartTime;
19988  LockedRouteFoundDuringRouteBuilding = true;
19989  LockedRouteVector.erase(LRVIT);
19990  }
19991  }
19992  }
19993  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
19994  {
19995  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
19996  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
19997  }
19998  Utilities->CallLogPop(395);
19999 }
20000 
20001 // ---------------------------------------------------------------------------
20002 
20004  TRoute2MultiMapIterator &Route2MultiMapIterator)
20005 /*
20006  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
20007  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
20008  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
20009  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
20010  are given for failure.
20011 */
20012 {
20013  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
20014  AnsiString(VLoc) + "," + AnsiString(ELink));
20015  TRouteElementPair ReturnPair;
20016 
20017  ReturnPair.first = -1;
20018  ReturnPair.second = 0;
20019  THVPair Route2MultiMapKeyPair;
20020 
20021  Route2MultiMapKeyPair.first = HLoc;
20022  Route2MultiMapKeyPair.second = VLoc;
20023  TRoute2MultiMapEntry Route2MultiMapEntry;
20024 
20025  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
20026  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20027 
20028  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20029  Route2MultiMapIterator = ItPair.first;
20030 
20031  if(ItPair.first == ItPair.second)
20032  {
20033  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
20034  }
20035  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
20036  {
20037  ReturnPair.first = ItPair.first->second.first;
20038  ReturnPair.second = ItPair.first->second.second;
20039  Route2MultiMapIterator = ItPair.first;
20040  Utilities->CallLogPop(396);
20041  return(ReturnPair);
20042  }
20043  ItPair.first++;
20044  if(ItPair.first == ItPair.second)
20045  {
20046  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
20047  }
20048  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
20049  {
20050  ReturnPair.first = ItPair.first->second.first;
20051  ReturnPair.second = ItPair.first->second.second;
20052  Route2MultiMapIterator = ItPair.first;
20053  Utilities->CallLogPop(397);
20054  return(ReturnPair);
20055  }
20056  Utilities->CallLogPop(398);
20057  return(ReturnPair);
20058 }
20059 
20060 // ---------------------------------------------------------------------------
20061 
20062 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
20063 /*
20064  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
20065  Examines Route2MultiMap and returns true if a route is found with the passed values of H, V and ELink.
20066  RouteNumber (route position in AllRoutes vector is returned as a reference.
20067  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
20068  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
20069 */
20070 {
20071  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
20072  AnsiString(VLoc) + "," + AnsiString(ELink));
20073  THVPair Route2MultiMapKeyPair;
20074 
20075  Route2MultiMapKeyPair.first = HLoc;
20076  Route2MultiMapKeyPair.second = VLoc;
20077  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20078 
20079  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20080 
20081  if(ItPair.first == ItPair.second)
20082  {
20083  RouteNumber = -1;
20084  Utilities->CallLogPop(2032);
20085  return(false);
20086  }
20087  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
20088  {
20089  RouteNumber = ItPair.first->second.first;
20090  Utilities->CallLogPop(2033);
20091  return(true);
20092  }
20093  ItPair.first++;
20094 
20095  if(ItPair.first == ItPair.second)
20096  {
20097  RouteNumber = -1;
20098  Utilities->CallLogPop(2034);
20099  return(false);
20100  }
20101  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
20102  {
20103  RouteNumber = ItPair.first->second.first;
20104  Utilities->CallLogPop(2035);
20105  return(true);
20106  }
20107  RouteNumber = -1;
20108  Utilities->CallLogPop(2036);
20109  return(false);
20110 }
20111 
20112 // ---------------------------------------------------------------------------
20113 
20114 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
20115 /*
20116  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
20117  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
20118  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
20119  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
20120  Called by TAllRoutes::AddRouteElement.
20121 */
20122 {
20123  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
20124  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
20125  THVPair Route2MultiMapKeyPair;
20126 
20127  Route2MultiMapKeyPair.first = HLoc;
20128  Route2MultiMapKeyPair.second = VLoc;
20129  TRoute2MultiMapEntry Route2MultiMapEntry;
20130 
20131  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
20132  TRouteElementPair RouteElementPair;
20133 
20134  RouteElementPair.first = RouteNumber;
20135  RouteElementPair.second = RouteElementNumber;
20136  Route2MultiMapEntry.second = RouteElementPair;
20137 
20138  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
20139  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
20140  {
20141  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
20142  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
20143  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
20144  {
20145  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
20146  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
20147  {
20148  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
20149  }
20150  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
20151  }
20152  else
20153  // same ELink so have an error
20154  {
20155  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
20156  }
20157  }
20158  else
20159  {
20160  Route2MultiMap.insert(Route2MultiMapEntry);
20161  }
20162 // element at H&V not found in map so insert it
20163  Utilities->CallLogPop(399);
20164 }
20165 
20166 // ---------------------------------------------------------------------------
20167 
20169 /*
20170  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
20171  and the second in the reference SecondPair. If there's only one then it's the function return
20172 */
20173 {
20174  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
20175  AnsiString(VLoc));
20177 
20178  TempPair.first = -1;
20179  TempPair.second = 0;
20180  SecondPair = TempPair;
20181  TRoute2MultiMapIterator Route2MultiMapIterator;
20182  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
20183  THVPair Route2MultiMapKeyPair;
20184 
20185  Route2MultiMapKeyPair.first = HLoc;
20186  Route2MultiMapKeyPair.second = VLoc;
20187  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
20188  {
20189  Utilities->CallLogPop(400);
20190  return(TempPair);
20191  }
20192  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
20193  {
20194  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
20195  Utilities->CallLogPop(401);
20196  return(Route2MultiMapIterator->second);
20197  }
20198  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
20199  {
20200  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20201  TempPair = ItRange.first->second;
20202  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
20203  Utilities->CallLogPop(402);
20204  return(TempPair);
20205  }
20206  Utilities->CallLogPop(403);
20207  return(TempPair);
20208 }
20209 
20210 // ---------------------------------------------------------------------------
20211 
20212 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
20213 /*
20214  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
20215  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
20216 */
20217 {
20218  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
20219  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
20220  {
20221  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
20222  {
20223  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
20224  TAllRoutes::TRouteElementPair SecondPair;
20225  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
20226  if(RouteElementPair.first == -1)
20227  // failed to find element in multimap
20228  {
20229  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
20230  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
20231  }
20232  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
20233  // neither pair has expected route number
20234  {
20235  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
20236  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
20237  (AnsiString)Caller);
20238  }
20239  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
20240  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
20241  {
20242  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
20243  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
20244  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
20245  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
20246  }
20247  }
20248  }
20249  unsigned int SizeVal = 0;
20250 
20251 // check map and sum of route sizes match
20252  for(unsigned int a = 0; a < AllRoutesSize(); a++)
20253  {
20254  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
20255  }
20256  if(SizeVal != Route2MultiMap.size())
20257  {
20258  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
20259  (AnsiString)Caller);
20260  }
20261  Utilities->CallLogPop(404);
20262  return;
20263 }
20264 
20265 // ---------------------------------------------------------------------------
20266 
20267 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
20268 /*
20269  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
20270  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
20271  exceed that for the erased route. Where this is so the RouteNumber is decremented.
20272 */
20273 {
20274  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
20275  if(!Route2MultiMap.empty())
20276  {
20277  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
20278  {
20279  if(Route2MultiMapIterator->second.first > RouteNumber)
20280  {
20281  Route2MultiMapIterator->second.first--;
20282  }
20283  }
20284  }
20285  Utilities->CallLogPop(405);
20286 }
20287 
20288 // ---------------------------------------------------------------------------
20289 
20290 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
20291 /*
20292  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
20293  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
20294  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
20295 */
20296 {
20297  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
20298  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
20299  if(!Route2MultiMap.empty())
20300  {
20301  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
20302  {
20303  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
20304  {
20305  Route2MultiMapIterator->second.second--;
20306  }
20307  }
20308  }
20309  Utilities->CallLogPop(406);
20310 }
20311 
20312 // ---------------------------------------------------------------------------
20313 
20314 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
20315 /*
20316  Erases the route element from Route2MultiMap and from the PrefDirVector.
20317  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
20318  decremented if they are greater than the element number removed, and if the entire route is removed
20319  then the route numbers are also decremented in the map for route numbers that are greater than the route
20320  number that is removed.
20321 */
20322 {
20323  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
20324  AnsiString(ELink));
20325  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
20326  TRoute2MultiMapIterator Route2MultiMapIterator;
20327 
20328  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
20329  if(RequiredRoutePair.first == -1)
20330  {
20331  throw Exception("Failed to find route element in RemoveRouteElement");
20332  }
20333  Route2MultiMap.erase(Route2MultiMapIterator);
20334  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
20335 
20336 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
20337  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
20338 
20339  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
20340  {
20341  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
20342  }
20343 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
20344 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
20345 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
20346 // to check if a route element is present, and the element has already been removed from the map - see above.
20347 
20348 // before erase the element check if it's in a locked route, and if so change the RearTrackVectorPosition to the next valid (XLinkPos] element position
20349 /*
20350  int LockedVectorNumber = -1;
20351  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
20352  {
20353  LockedRouteVector.at(LockedVectorNumber).RearTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
20354  }
20355 */
20356 
20357 // erase element from route
20358  GetModifiableRouteAt(8, RequiredRoutePair.first).PrefDirVector.erase(GetModifiableRouteAt(33, RequiredRoutePair.first).PrefDirVector.begin() + RequiredRoutePair.second);
20359 // CheckMapAndRoutes();//test - drop - tested below
20360 
20361 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
20362 // be so as continuation exit is at the end of the route, and truncation is from the end
20364  {
20366  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
20367  AutoSigVectorIT--)
20368  {
20369  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
20370  {
20371  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
20372  }
20373  }
20374  }
20375 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
20376 // and adjust all the corresponding route numbers
20377  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
20378  {
20379  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
20380  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
20381  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
20382 
20383 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
20384  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
20385  it is erased then - see TInterface::ApproachLocking
20386 
20387  if(LockedVectorNumber > -1)
20388  {
20389  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
20390  }
20391 */
20392  // decrement route numbers in the locked route vector whether or not this route is a locked route
20393  if(!LockedRouteVector.empty())
20394  {
20395  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20396  {
20397  if(LRVIT->RouteNumber > RequiredRoutePair.first)
20398  {
20399  LRVIT->RouteNumber--;
20400  }
20401  }
20402  }
20404  {
20406  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
20407  AutoSigVectorIT--)
20408  {
20409  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
20410  {
20411  AutoSigVectorIT->RouteNumber--;
20412  }
20413  }
20414  }
20415  }
20416  CheckMapAndRoutes(7); // test
20417  Utilities->CallLogPop(407);
20418 }
20419 
20420 // ---------------------------------------------------------------------------
20421 
20422 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
20423 /*
20424  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
20425  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
20426  since that catches all route elements wherever created
20427 */
20428 {
20429  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
20430  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
20431  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
20432  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1); //-1 because vector has been increased by 1 above, so
20433  Utilities->CallLogPop(408); //PrefDirSize() has been increased by 1, so the new element
20434 } //number is one less than this
20435 
20436 // ---------------------------------------------------------------------------
20437 
20438 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
20439 /*
20440  Enter with signal at TrackVectorElement already set to red by the passing train.
20441  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
20442  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
20443  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
20444  case the function sets no further signals - if rear route is non-autosigs then no route behind train, if autosigs the train will have
20445  set signals in rear as it passed them.
20446 */
20447 {
20448  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
20449  "," + AnsiString(XLinkPos));
20450  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
20451  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
20452 
20453  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
20454  if(RouteElementPair.first == -1)
20455  {
20456  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
20457  }
20458  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
20459 
20460  RequiredPair = RouteElementPair;
20461  if(RouteElement.XLinkPos != XLinkPos)
20462  {
20463  if(SecondPair.first != -1)
20464  {
20465  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
20466  RequiredPair = SecondPair;
20467  if(RouteElement.XLinkPos != XLinkPos)
20468  {
20469  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
20470  }
20471  }
20472  else
20473  {
20474  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
20475  }
20476  }
20477 // new function
20478  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
20479  Utilities->CallLogPop(409);
20480 }
20481 
20482 // ---------------------------------------------------------------------------
20483 
20484 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber) //minor changes at v2.17.0
20485 /*
20486  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
20487  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
20488  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
20489  accordingly, then double yellow, then green (for 4 aspect signals). There are only 3 calls in all for any given route, and the AccessNumber
20490  changes from 0 to 1 to 2 for successive calls.
20491  Initially Attribute is set to AccessNumber to correspond to the first signal attribute to be set, then a number of validity checks
20492  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
20493  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
20494  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals - if rear
20495  route is non-autosigs then no route behind train, if autosigs the train will have set signals in rear as it passes them.
20496 */
20497 {
20498  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
20499  AnsiString(AccessNumber));
20500  TPrefDirElement RouteElement;
20501  int Attribute = AccessNumber; //was +1, but at v2.17.0 access no. increment carried out before set signals so SetRouteSignals works ok whenever called
20502 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
20503  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
20504 
20505  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
20506  {
20507  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
20508  }
20509  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
20510  {
20511  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
20512  }
20513  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
20514  x).XLinkPos] != End)
20515  {
20516  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
20517  }
20518 // new function
20519  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
20520  Utilities->CallLogPop(410);
20521 }
20522 
20523 // ---------------------------------------------------------------------------
20524 
20525 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition) //some changes at v2.17.0
20526 /*
20527  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
20528  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
20529  or (b) in a linked rear route, in which case the function sets no further signals - if rear route is non-autosigs then no route behind train,
20530  if autosigs the train will have set signals in rear as it passed them.
20531 
20532  First call SetRearwardsSignalsReturnFalseForTrainInRear (which is only called by this function) to set signals in route RouteNumber according
20533  to the received or modified (because of the forward look for buffers or continuation etc.) Attribute. If no train is found during this call
20534  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrainInRear for each rearwards linked route (without a forward look)
20535  until either reach the beginning of the last linked route or find a train in a linked rear route. If a train is found in a linked rear route
20536  then the function terminates.
20537 
20538  However if a train is found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrainInRear then need to continue after the
20539  train for an autosigs route or in case had just added a route segment behind a train that now forms part of a single continuous route for a
20540  non-autosigs route, otherwise the signals won't be set behind the train.
20541 
20542  First the route is examined element by element from the RouteStartPosition towards the start of the
20543  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
20544  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
20545  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
20546  found behind the train.
20547 
20548  Description of SetRearwardsSignalsReturnFalseForTrainInRear for reference
20549  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
20550  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
20551  rearward search, first search forwards (unless SkipForwardLook true) from the PrefDirVectorStartPosition + 1 (may be in a forward route -
20552  see FindForwardTargetSignalAttribute) in case the end of the route is a buffer, continuation, or something else that requires Attribute
20553  to be modified and modify the Attribute accordingly UNLESS (a) train or closed LC present between PrefDirVectorStartPosition & end;
20554  (b) route in ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals),
20555  or (c) truncating a route.
20556 
20557  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
20558  signal or something else that requires Attribute to change. If find a signal set its Attribute to the current Attribute value up to a maximum
20559  of 3, and replot the signal as well as the required route and direction (if required) graphics, then increment Attribute up to a max. of 3
20560  [addition at v2.9.2: if signal or element beyond it is in a locked route then set signal to red & change Attribute to 0 - this fault reported
20561  by Simon Banham 21/07/21 as an image]. and continue working backwards for the next signal (or train - return false as before) and so on.
20562  On completion Attribute is passed back from the function as a reference. If no train is found before the beginning of the route is reached
20563  the function returns true.
20564 
20565  In setting signals skip the first position if it's a signal and if truncating (can only truncate to signal if route is unrestricted) - otherwise
20566  the truncated signal counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
20567 */
20568 {
20569  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
20570  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
20571  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
20572  int RearwardLinkedRouteNumber;
20573 
20574 // Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes {dropped at v2.17.0 as not used)
20575  bool SkipForwardLook = false; //allow forward look in first call
20576  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrainInRear(1, Attribute, RouteStartPosition, SkipForwardLook)) // updates
20577  //Attribute to 1+ final signal value in the route for use in further linked routes
20578  {
20579  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1 (no
20580  { //linked rearwards route)
20581  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
20582  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute) //keep setting signals on each rear route until find a train or no more routes
20583  {
20584  SkipForwardLook = true; //don't want forward look for subsequent rearwards linked routes
20585  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrainInRear(2, Attribute, AllRoutes->GetFixedRouteAt(130,
20586  RearwardLinkedRouteNumber).PrefDirSize() - 1, SkipForwardLook)))
20587  {
20588  break;
20589  }
20590  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
20591  }
20592  }
20593  }
20594  else // found a train in this route (in RouteNumber) before the beginning of the route, so need to continue setting signals after the train
20595  {
20596  int TrainID, TrainPosition, BehindTrainPosition;
20597  bool FoundTrain = false, BehindTrain = false;
20598  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
20599  {
20600  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
20601  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
20602  TrainID = TrackElement.TrainIDOnElement;
20603  if(TrackElement.TrackType == Bridge)
20604  {
20605  if(PrefDirElement.XLinkPos < 2)
20606  {
20607  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20608  }
20609  else
20610  {
20611  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20612  }
20613  }
20614  if(TrainID == -1)
20615  {
20616  continue;
20617  }
20618  else
20619  {
20620  FoundTrain = true;
20621  TrainPosition = x;
20622  break;
20623  }
20624  }
20625  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then this route doesn't continue behind the train so can stop.
20626  { //If there is a linked rear route then no need to deal with signals behind train here -
20627  //if rear route is non-autosigs then no route behind train, if autosigs the train will have
20628  //set signals in rear as it passed them.
20629  for(int x = TrainPosition; x >= 0; x--) // now step back from that position until find element behind the train - ignore any
20630  { // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
20631  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
20632  // need the element behind the rearmost train.
20633  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
20634  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
20635  TrainID = TrackElement.TrainIDOnElement;
20636  if(TrackElement.TrackType == Bridge)
20637  {
20638  if(PrefDirElement.XLinkPos < 2)
20639  {
20640  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20641  }
20642  else
20643  {
20644  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20645  }
20646  }
20647  if(TrainID != -1)
20648  {
20649  continue; // still on train
20650  }
20651  else
20652  {
20653  BehindTrain = true;
20654  BehindTrainPosition = x;
20655  break;
20656  }
20657  }
20658  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
20659  // so on for as many trains as there are on this (RouteNumber) route
20660  {
20661  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // Although SkipForwardLook will be false when
20662  //SetRearwardsSignalsReturnFalseForTrainInRear is first called the forward look will find the train so Attribute will be set to 0
20663  } //for rearward signal setting
20664  }
20665  }
20666  Utilities->CallLogPop(411);
20667 }
20668 
20669 // ---------------------------------------------------------------------------
20670 
20671 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int LookBackwardsFromHere)
20672 {
20673 /* Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTruncatePosition on the route itself or on any linked routes,
20674 unless the first signal back is red, or a train on the element immediately before the start of the rearmost linked route (i.e. not on a route but about to enter the
20675 rearmost linked route) - this because train cancels route elements that it touches)
20676 */
20677  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
20678  AnsiString(LookBackwardsFromHere));
20679  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber;
20680  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
20681  TPrefDirElement PrefDirElement, FirstElement;
20682  TTrackElement TrackElement;
20683  bool ExamineRoute = true;
20684 
20685  while(ExamineRoute)
20686  {
20687  for(int x = LookBackwardsFromHere; x >= 0; x--) //work back along the route from the start position
20688  {
20689  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
20690  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
20691  TrainID = TrackElement.TrainIDOnElement;
20692  if(TrackElement.TrackType == Bridge)
20693  {
20694  if(PrefDirElement.XLinkPos < 2)
20695  {
20696  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20697  }
20698  else
20699  {
20700  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20701  }
20702  }
20703  if(TrainID > -1)
20704  {
20705  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
20706  {
20707  //any trains further back in route will be protected by the red signal behind the stopped train
20708  Utilities->CallLogPop(412);
20709  return(false);
20710  }
20711  //added at v2.4.2 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
20712  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
20713  //other way & can cancel the route
20714  {
20715  Utilities->CallLogPop(2203);
20716  return(false);
20717  }
20718  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
20719  return(true); //MovingTrainOccupyingRoute which is outside this function but also causes route locking)
20720  }
20721  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
20722  {
20723  if(TrackElement.Attribute == 0)
20724  {
20725  Utilities->CallLogPop(413);
20726  return(false); // OK, red signal in front of a train
20727  }
20728  if(TrackElement.SigAspect != TTrackElement::GroundSignal) //ignore ground signals
20729  {
20730  SignalCount++;
20731  }
20732  if(SignalCount >= 3)
20733  {
20734  Utilities->CallLogPop(414);
20735  return(false);
20736  }
20737  }
20738  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
20739  // ElinkPos because working back along PrefDir to beginning
20740  {
20741  Utilities->CallLogPop(415);
20742  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
20743  }
20744  }
20745  //now look at linked rearwards routes
20746  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
20747  LookBackwardsFromHere = CurrentRoute.PrefDirSize() - 1;
20748  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
20749  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
20750  {
20751  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
20752  ExamineRoute = true;
20753  LookBackwardsFromHere = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
20754  }
20755  else
20756  {
20757  // here check for a train on the element immediately before the first route element (i.e. not on a route but about to enter the rearmost linked route)
20758  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
20759  TrainID = PriorTrackElement.TrainIDOnElement;
20760  if(PriorTrackElement.TrackType == Bridge)
20761  {
20762  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
20763  {
20764  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20765  }
20766  else
20767  {
20768  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20769  }
20770  }
20771  if(TrainID > -1)
20772  {
20773  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
20774  {
20775  Utilities->CallLogPop(748);
20776  return(false);
20777  }
20778  //added at v2.4.2 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
20779  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
20780  //other way & can cancel the route
20781  {
20782  Utilities->CallLogPop(2204);
20783  return(false);
20784  }
20785  Utilities->CallLogPop(1962);
20786  return(true); //otherwise need to lock the route
20787  }
20788  ExamineRoute = false;
20789  }
20790  }
20791 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
20792 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
20793  Utilities->CallLogPop(416);
20794  return(false);
20795 }
20796 
20797 // ---------------------------------------------------------------------------
20798 
20799 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
20800  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
20801 {
20802  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
20803  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
20804  TPrefDirElement InternalPrefDirElement; // blank element
20805 
20806  PrefDirElement = InternalPrefDirElement;
20807  if(LockedRouteVector.empty())
20808  {
20809  Utilities->CallLogPop(417);
20810  return(false);
20811  }
20812 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
20813 // even if some elements have been removed from the front by a train
20814  bool InLockedRoute = false;
20815 
20816  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20817  {
20818  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
20819  {
20820  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
20821  // doesn't arise)
20822  InLockedRoute = true;
20823  break;
20824  }
20825  }
20826  if(!InLockedRoute)
20827  {
20828  Utilities->CallLogPop(418);
20829  return(false);
20830  }
20831  int RouteNumber, VectorCount = 0;
20832  TRouteType RouteType;
20833 
20834  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20835  {
20836  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
20837  if(RouteType == NoRoute)
20838  {
20839  continue;
20840  }
20841 /* can't use this test with front truncation
20842  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
20843  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
20844  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
20845  {
20846  throw Exception
20847  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
20848  }
20849 */
20850  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
20851  {
20852  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
20853  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->RearTrackVectorPosition)
20854  {
20855  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
20856  {
20857  PrefDirElement = InternalPrefDirElement;
20858  LockedVectorNumber = VectorCount;
20859  Utilities->CallLogPop(419);
20860  return(true);
20861  }
20862  }
20863  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->RearTrackVectorPosition)
20864  {
20865  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
20866  {
20867  PrefDirElement = InternalPrefDirElement;
20868  LockedVectorNumber = VectorCount;
20869  Utilities->CallLogPop(420);
20870  return(true);
20871  }
20872  else
20873  {
20874  break; // reached & tested LRVIT->RearTrackVectorPosition for a match so don't want to go any further for this route
20875  }
20876  }
20877  }
20878  VectorCount++;
20879  }
20880  Utilities->CallLogPop(421);
20881  return(false);
20882 }
20883 
20884 // ---------------------------------------------------------------------------
20885 
20887 {
20888  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
20889  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20890  {
20891  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
20892  {
20893  Utilities->CallLogPop(963);
20894  return(x);
20895  }
20896  }
20897  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
20898 }
20899 
20900 // ---------------------------------------------------------------------------
20901 
20903 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
20904 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
20905 {
20906  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
20907  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20908  {
20909  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
20910  {
20911  Utilities->CallLogPop(2039);
20912  return(true);
20913  }
20914  }
20915  Utilities->CallLogPop(2040);
20916  return(false);
20917 }
20918 
20919 // ---------------------------------------------------------------------------
20920 
20922 {
20923  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
20924  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20925  {
20926  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
20927  {
20928  Utilities->CallLogPop(964);
20929  return(GetFixedRouteAt(159, x));
20930  }
20931  }
20932  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
20933 }
20934 
20935 // ---------------------------------------------------------------------------
20936 
20938 {
20939  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
20940  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20941  {
20942  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
20943  {
20944  Utilities->CallLogPop(965);
20945  return(GetModifiableRouteAt(15, x));
20946  }
20947  }
20948  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
20949 }
20950 
20951 // ---------------------------------------------------------------------------
20952 
20953 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
20954 {
20955  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
20956  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
20957  Utilities->SaveFileInt(OutFile, NextRouteID);
20958  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20959  {
20960  TOneRoute OneRoute = GetFixedRouteAt(165, x);
20961  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
20962  OneRoute.SavePrefDirVector(6, OutFile);
20963  }
20964  Utilities->CallLogPop(1442);
20965 }
20966 
20967 // ---------------------------------------------------------------------------
20968 
20969 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
20970 {
20971  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
20972  int NumberOfRoutes;
20973 
20974  NumberOfRoutes = Utilities->LoadFileInt(InFile);
20975  NextRouteID = Utilities->LoadFileInt(InFile);
20976  for(int x = 0; x < NumberOfRoutes; x++)
20977  {
20978  TOneRoute OneRoute; // empty route
20979  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
20980  OneRoute.LoadPrefDir(2, InFile);
20982  {
20983  StoreOneRouteAfterSessionLoad(0, &OneRoute);
20984  }
20985  else
20986  {
20987  Utilities->CallLogPop(1443);
20988  return(false);
20989  }
20990  }
20991  Utilities->CallLogPop(1444);
20992  return(true);
20993 }
20994 
20995 // ---------------------------------------------------------------------------
20996 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
20997 {
20998  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
20999  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
21000 
21001  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
21002  {
21003  Utilities->CallLogPop(1445);
21004  return(false);
21005  }
21006  int NextID = Utilities->LoadFileInt(InFile);
21007 
21008  if((NextID < 0) || (NextID > 1000000))
21009  {
21010  Utilities->CallLogPop(1446);
21011  return(false);
21012  }
21013  for(int x = 0; x < NumberOfRoutes; x++)
21014  {
21015  int RouteID = Utilities->LoadFileInt(InFile);
21016  if((RouteID < 0) || (RouteID > 20000))
21017  {
21018  Utilities->CallLogPop(1447);
21019  return(false);
21020  }
21021  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
21022  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
21023  {
21024  Utilities->CallLogPop(1448);
21025  return(false);
21026  }
21027  }
21028  Utilities->CallLogPop(1449);
21029  return(true);
21030 }
21031 
21032 // ---------------------------------------------------------------------------
21033 
21034 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
21035 {
21036  // return true for a loop
21037  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
21038  AnsiString(StartPosition));
21039  if(EndPosition == StartPosition)
21040  {
21041  Utilities->CallLogPop(1839);
21042  return(true); // shouldn't happen but treat as a loop if does
21043  }
21044 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
21045  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
21046  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
21047 
21048  while(TrackIsInARoute(15, TVPos, LkPos))
21049  {
21050  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
21051  int NewLkPos = -1;
21052  if(NewTVPos > -1)
21053  {
21054  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
21055  if(NewLkPos == -1)
21056  {
21057  Utilities->CallLogPop(1840);
21058  return(true); // shouldn't arise but treat as loop if does
21059  }
21060  }
21061  else // reached a buffer or continuation
21062  {
21063  Utilities->CallLogPop(1841);
21064  return(false);
21065  }
21066 //Error found by Xeon notified by email 13/10/20.
21067 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
21068 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
21069 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
21070 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
21071 //New check added for v2.6.0
21072 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
21073 //as possible in case there are other unforeseen effects.
21074  int RouteNumber; //dummy, not used
21075  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
21076  {
21077  Utilities->CallLogPop(2241);
21078  return(false);
21079  }
21080  //now make the connected element the current element, read across the TV number and determine the exit link
21081  TVPos = NewTVPos;
21082  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
21083  {
21084  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
21085  {
21086  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
21087  {
21088  LkPos = 1;
21089  }
21090  else
21091  {
21092  LkPos = 3;
21093  }
21094  }
21095  else
21096  {
21097  LkPos = 0;
21098  }
21099  }
21100  else
21101  {
21102  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
21103  }
21104  if(TVPos == StartPosition)
21105  {
21106  Utilities->CallLogPop(1842);
21107  return(true); // it is a loop
21108  }
21109  }
21110  Utilities->CallLogPop(1843);
21111  return(false); // reached end of route so not a loop
21112 }
21113 
21114 // ---------------------------------------------------------------------------
21115 
21116 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
21117 /*
21118  Track geometry allows diagonals to cross without occupying the same track element, so when
21119  route plotting it is necessary to check if there is an existing route or a train on such a crossing
21120  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
21121  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
21122  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
21123  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
21124  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
21125  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
21126  Each of these is examined in turn for each route element in the relevant position.
21127 
21128  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
21129  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
21130  that returns false in all cases (including elements & links not present) except train present.
21131 */
21132 {
21133  int TrainID; // not used in this function
21134 
21135  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
21136  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
21137  TPrefDirElement TempPrefDirElement;
21138  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
21139 
21140  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
21141  if(FirstPair.first > -1)
21142  {
21143  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
21144  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21145  {
21146  Utilities->CallLogPop(310);
21147  return(true);
21148  }
21149  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21150  {
21151  Utilities->CallLogPop(311);
21152  return(true);
21153  }
21154  }
21155  if(SecondPair.first > -1)
21156  {
21157  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
21158  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21159  {
21160  Utilities->CallLogPop(312);
21161  return(true);
21162  }
21163  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21164  {
21165  Utilities->CallLogPop(313);
21166  return(true);
21167  }
21168  }
21169  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
21170  9, TrainID)))
21171  {
21172  Utilities->CallLogPop(1997);
21173  return(true);
21174  }
21175  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
21176  if(FirstPair.first > -1)
21177  {
21178  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
21179  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21180  {
21181  Utilities->CallLogPop(314);
21182  return(true);
21183  }
21184  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21185  {
21186  Utilities->CallLogPop(315);
21187  return(true);
21188  }
21189  }
21190  if(SecondPair.first > -1)
21191  {
21192  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
21193  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21194  {
21195  Utilities->CallLogPop(316);
21196  return(true);
21197  }
21198  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21199  {
21200  Utilities->CallLogPop(317);
21201  return(true);
21202  }
21203  }
21204  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
21205  9, TrainID)))
21206  {
21207  Utilities->CallLogPop(1998);
21208  return(true);
21209  }
21210  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
21211  if(FirstPair.first > -1)
21212  {
21213  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
21214  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21215  {
21216  Utilities->CallLogPop(318);
21217  return(true);
21218  }
21219  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21220  {
21221  Utilities->CallLogPop(319);
21222  return(true);
21223  }
21224  }
21225  if(SecondPair.first > -1)
21226  {
21227  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
21228  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21229  {
21230  Utilities->CallLogPop(320);
21231  return(true);
21232  }
21233  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21234  {
21235  Utilities->CallLogPop(321);
21236  return(true);
21237  }
21238  }
21239  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
21240  7, TrainID)))
21241  {
21242  Utilities->CallLogPop(1999);
21243  return(true);
21244  }
21245  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
21246  if(FirstPair.first > -1)
21247  {
21248  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
21249  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21250  {
21251  Utilities->CallLogPop(322);
21252  return(true);
21253  }
21254  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21255  {
21256  Utilities->CallLogPop(323);
21257  return(true);
21258  }
21259  }
21260  if(SecondPair.first > -1)
21261  {
21262  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
21263  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21264  {
21265  Utilities->CallLogPop(324);
21266  return(true);
21267  }
21268  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21269  {
21270  Utilities->CallLogPop(325);
21271  return(true);
21272  }
21273  }
21274  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
21275  3, TrainID)))
21276  {
21277  Utilities->CallLogPop(2000);
21278  return(true);
21279  }
21280  Utilities->CallLogPop(326);
21281  return(false);
21282 }
21283 
21284 // ---------------------------------------------------------------------------
21285 
21286 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
21287 /*
21288  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
21289  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
21290  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
21291  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
21292  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
21293  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
21294  Each of these is examined in turn for each route element in the relevant position.
21295 */
21296 {
21297  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
21298  "," + AnsiString(DiagonalLinkNumber));
21299  TPrefDirElement TempPrefDirElement;
21300  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
21301 
21302  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
21303  if(FirstPair.first > -1)
21304  {
21305  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
21306  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21307  {
21308  Utilities->CallLogPop(2010);
21309  return(true);
21310  }
21311  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21312  {
21313  Utilities->CallLogPop(2011);
21314  return(true);
21315  }
21316  }
21317  if(SecondPair.first > -1)
21318  {
21319  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
21320  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21321  {
21322  Utilities->CallLogPop(2012);
21323  return(true);
21324  }
21325  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21326  {
21327  Utilities->CallLogPop(2013);
21328  return(true);
21329  }
21330  }
21331  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
21332  if(FirstPair.first > -1)
21333  {
21334  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
21335  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21336  {
21337  Utilities->CallLogPop(2014);
21338  return(true);
21339  }
21340  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21341  {
21342  Utilities->CallLogPop(2015);
21343  return(true);
21344  }
21345  }
21346  if(SecondPair.first > -1)
21347  {
21348  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
21349  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21350  {
21351  Utilities->CallLogPop(2016);
21352  return(true);
21353  }
21354  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21355  {
21356  Utilities->CallLogPop(2017);
21357  return(true);
21358  }
21359  }
21360  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
21361  if(FirstPair.first > -1)
21362  {
21363  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
21364  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21365  {
21366  Utilities->CallLogPop(2018);
21367  return(true);
21368  }
21369  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21370  {
21371  Utilities->CallLogPop(2019);
21372  return(true);
21373  }
21374  }
21375  if(SecondPair.first > -1)
21376  {
21377  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
21378  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21379  {
21380  Utilities->CallLogPop(2020);
21381  return(true);
21382  }
21383  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21384  {
21385  Utilities->CallLogPop(2021);
21386  return(true);
21387  }
21388  }
21389  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
21390  if(FirstPair.first > -1)
21391  {
21392  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
21393  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21394  {
21395  Utilities->CallLogPop(2022);
21396  return(true);
21397  }
21398  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21399  {
21400  Utilities->CallLogPop(2023);
21401  return(true);
21402  }
21403  }
21404  if(SecondPair.first > -1)
21405  {
21406  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
21407  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21408  {
21409  Utilities->CallLogPop(2024);
21410  return(true);
21411  }
21412  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21413  {
21414  Utilities->CallLogPop(2025);
21415  return(true);
21416  }
21417  }
21418  Utilities->CallLogPop(2026);
21419  return(false);
21420 }
21421 
21422 // ---------------------------------------------------------------------------
21423 
21424 
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:9658
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:696
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:481
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:19518
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1329
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:953
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:468
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:12259
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:682
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:749
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:37
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:632
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:584
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:12232
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:439
TTrack::ResetTSRs
void ResetTSRs(int Caller)
Called on exit from operation to reset failed to false for all simple track elements & clear TSRVecto...
Definition: TrackUnit.cpp:4793
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:573
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:51
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:81
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:357
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:894
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5668
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:13777
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:791
TFixedTrackPiece
Definition: TrackUnit.h:83
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:128
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1745
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:814
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:425
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:944
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:20114
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:92
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:810
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:247
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:945
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:10245
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:812
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:20525
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:956
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1383
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:513
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:806
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:600
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:721
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:14301
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:778
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:639
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:824
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:437
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:13817
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:698
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3843
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:719
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:399
PerfLogForm
TPerfLogForm * PerfLogForm
Definition: PerfLogUnit.cpp:11
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:458
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:900
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:804
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:287
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7440
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:471
TAllRoutes::SearchAllRoutesAndTruncate
bool SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in that...
Definition: TrackUnit.cpp:19480
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:97
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:703
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1725
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:730
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5820
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7341
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5847
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1539
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:593
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1686
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:67
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:845
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:866
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1977
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:934
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10698
TRailGraphics::FGSig70
Graphics::TBitmap * FGSig70
Definition: GraphicUnit.h:928
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:623
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:631
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:942
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:21286
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:439
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1716
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:70
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:614
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2885
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:488
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:558
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:6000
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:747
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:691
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:464
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Definition: TrackUnit.h:153
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8368
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
Definition: TrackUnit.h:1549
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:652
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:19952
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:782
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:585
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:685
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:13556
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:364
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7826
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:487
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:405
TTrackElement::StationEntryStopLinkPos3
int StationEntryStopLinkPos3
Definition: TrackUnit.h:153
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:10943
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9621
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:14950
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:49
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:17218
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:585
TTrack::TActiveLevelCrossing::TActiveLevelCrossing
TActiveLevelCrossing()
constructor, sets default values
Definition: TrackUnit.cpp:1141
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:20314
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:876
TTrack::NoPlatsMessageSent
bool NoPlatsMessageSent
used to send no platforms warning once only
Definition: TrackUnit.h:762
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:874
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:498
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1666
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:892
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:552
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:13360
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:161
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:517
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4544
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3723
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:692
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:850
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1563
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:463
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:601
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:779
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:470
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:815
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:8183
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:445
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:681
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:604
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1046
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4704
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1343
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6624
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:11537
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:673
TRailGraphics::FGSig71
Graphics::TBitmap * FGSig71
Definition: GraphicUnit.h:929
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:521
TRailGraphics::FGSig69
Graphics::TBitmap * FGSig69
Definition: GraphicUnit.h:927
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:887
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3599
Unused
@ Unused
Definition: TrackUnit.h:66
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:606
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:636
TTrack::OneStationLongEnoughForSplit
bool OneStationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:10947
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1342
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:494
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:724
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:20799
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2918
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:789
TTrack::ResetAllTrainIDsAndFailedPointOrigSpeedLimits
void ResetAllTrainIDsAndFailedPointOrigSpeedLimits(int Caller)
Definition: TrackUnit.cpp:7812
TRailGraphics::FSig75
Graphics::TBitmap * FSig75
Definition: GraphicUnit.h:925
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:228
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:20996
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:581
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9790
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1724
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1561
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1653
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:210
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:954
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:35
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:732
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:443
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:839
TTrack::SimpleVector
TSimpleVector SimpleVector
vector of simple element track vector positions
Definition: TrackUnit.h:820
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3323
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:16711
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:35
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:222
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:796
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:688
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:504
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8660
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:13622
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:808
Simple
@ Simple
Definition: TrackUnit.h:66
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:448
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:77
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:482
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:813
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2934
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:732
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1042
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:20062
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:794
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:838
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:429
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1410
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:725
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:13873
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3920
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1783
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:614
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5960
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:689
TTrain
Definition: TrainUnit.h:303
TTrack::FailedGroundSigTable
TSigElement FailedGroundSigTable[8]
table of failed signals added at v2.13.0
Definition: TrackUnit.h:745
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:382
TTrack::SetNonStationStopLinkEntryPosses
void SetNonStationStopLinkEntryPosses(int Caller)
similar to SetStationEntryStopLinkPosses but for non-station named elements
Definition: TrackUnit.cpp:10461
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:14821
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:508
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:117
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:12273
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:497
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:580
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:577
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:861
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:633
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7841
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:420
TPerfLogForm::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: PerfLogUnit.cpp:32
TUtilities::DefaultTrackLength
int DefaultTrackLength
length of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:89
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:351
GapJump
@ GapJump
Definition: TrackUnit.h:66
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:447
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:809
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:20422
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:875
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7587
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:151
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:476
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:957
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:462
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:151
TTrack::Raising
@ Raising
Definition: TrackUnit.h:614
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:647
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:575
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10803
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:585
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:79
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1565
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1527
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:717
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:370
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:705
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:587
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:810
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:390
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:780
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:457
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:734
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1419
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:6248
End
@ End
Definition: TrackUnit.h:76
TUserGraphicItem
Definition: DisplayUnit.h:32
TUtilities::FixedMinRepairTime
int FixedMinRepairTime
Definition: Utilities.h:72
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1567
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:687
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:862
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:625
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:9014
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:883
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:940
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:139
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:42
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:570
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:10912
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1055
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:305
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:819
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:748
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:72
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:816
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:597
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:950
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:125
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:742
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:496
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:777
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:788
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3894
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:1026
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:875
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:1027
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:232
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:442
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:529
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:720
SignalPost
@ SignalPost
Definition: TrackUnit.h:66
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9755
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1036
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:466
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:19468
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:509
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:797
TOneRoute::SetRearwardsSignalsReturnFalseForTrainInRear
bool SetRearwardsSignalsReturnFalseForTrainInRear(int Caller, int &Attribute, int PrefDirVectorStartPosition, bool SkipForwardLook) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:18269
TAllRoutes::TAllRoutesVectorIterator
std::vector< TOneRoute >::iterator TAllRoutesVectorIterator
Definition: TrackUnit.h:1680
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1091
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1690
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:811
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:846
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7855
TRailGraphics::FGSig68
Graphics::TBitmap * FGSig68
Definition: GraphicUnit.h:926
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:461
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:675
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:408
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:7033
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:650
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:230
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:495
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:704
TRailGraphics::FSig71
Graphics::TBitmap * FSig71
Definition: GraphicUnit.h:921
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:37
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:9053
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:943
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:836
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call,...
Definition: TrackUnit.cpp:19453
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:775
Concourse
@ Concourse
Definition: TrackUnit.h:67
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:593
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:676
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:828
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:820
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:75
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:14590
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:14327
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:236
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:733
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:928
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:65
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:507
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4629
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1927
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:432
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:833
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:438
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:848
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:485
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:613
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:823
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:437
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:499
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:36
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:788
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:477
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:94
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:435
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:835
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:594
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:11740
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:20267
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4889
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:161
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1946
TTrack::MultiplayerOverlayMap
TMultiplayerOverlayMap MultiplayerOverlayMap
Definition: TrackUnit.h:798
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:693
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:808
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:961
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:764
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:565
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:91
TAllRoutes::Route2MultiMap
TRoute2MultiMap Route2MultiMap
the map that stores the elements of all routes on the railway (see TRoute2MultiMap for more info)
Definition: TrackUnit.h:1749
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:605
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:739
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:854
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:471
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:660
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11985
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:20902
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:593
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1053
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:630
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2902
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:729
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1573
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:15825
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7468
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8850
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7547
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:686
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:740
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5871
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:697
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:679
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
Definition: TrainUnit.h:318
TOneRoute::QuitAllRecursiveSearchesFlag
bool QuitAllRecursiveSearchesFlag
< limit to the number of elements searched in attempting to find a route in on leg
Definition: TrackUnit.h:1553
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:688
TOneRoute::ReclaimSignalsForNonAutoSigRoutes
void ReclaimSignalsForNonAutoSigRoutes(int caller, TPrefDirElement LastPDElement, TPrefDirElement FirstPDElement)
Adds signal to front/end of green or red routes when blue route truncated or removed.
Definition: TrackUnit.cpp:18973
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1345
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:875
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:822
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:514
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:821
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:474
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:13961
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:785
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:886
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:13096
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1691
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1743
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:46
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:941
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:607
TTrack::TSRVector
TFailedElementVector TSRVector
vector of failed points with track vector positions & repair times for use in failure handling (new a...
Definition: TrackUnit.h:794
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:13589
TTrack::TInfrastructureFailureEntry::TVPos
int TVPos
Definition: TrackUnit.h:715
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:671
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:19099
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3700
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:170
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:14280
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:12028
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1829
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:783
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:940
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:500
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:584
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:6054
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1029
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:13409
Under
@ Under
Definition: TrackUnit.h:76
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:454
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:828
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:715
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:629
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:156
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2957
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:12285
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:12604
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:890
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:434
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:135
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:55
Lead
@ Lead
Definition: TrackUnit.h:76
TUtilities::FailureMode
TFailureMode FailureMode
specifies whether no failures or minor, moderate or major random failures are to be applied (added at...
Definition: Utilities.h:119
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5919
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1863
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:14528
TTrack::PlotContinuation
void PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a continuation on screen, may have overlays if a multiplayer session.
Definition: TrackUnit.cpp:6131
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:894
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:555
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5711
TOneRoute::TruncateRoute
void TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:18516
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6605
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:86
TUtilities::SignalChangeEventsPerFailure
int SignalChangeEventsPerFailure
number of signal changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:95
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1374
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9549
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:472
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:473
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:598
TTrack::TInfrastructureFailureEntry
Definition: TrackUnit.h:714
TTrack::Up
@ Up
Definition: TrackUnit.h:614
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:882
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:830
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:588
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:10926
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:960
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1521
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:378
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8817
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1684
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:760
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:206
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:19186
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1673
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:367
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:800
Crossover
@ Crossover
Definition: TrackUnit.h:66
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6491
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:479
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:450
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:832
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:642
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8763
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:802
TRailGraphics::BlackOctagon
Graphics::TBitmap * BlackOctagon
Definition: GraphicUnit.h:577
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7496
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:10218
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:456
Signal
@ Signal
Definition: TrackUnit.h:76
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:575
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:593
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:465
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:796
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:19755
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1597
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:13459
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:510
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:11924
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4713
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:573
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:10898
TGraphicElement::Width
int Width
Definition: TrackUnit.h:441
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:20671
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:524
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:20886
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:19581
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:802
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:492
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:800
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:589
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:663
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:451
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or ' ' (CRLF) accepted as delimiters), returns true for succes...
Definition: Utilities.cpp:529
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:790
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:34
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:15359
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:662
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4202
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2418
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:695
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:469
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9689
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks, bool PerformNameSearch)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2160
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to display EveryPrefDir - red for unidirectional PrefDir & gre...
Definition: TrackUnit.cpp:13227
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:608
TTrack::FailedSignalsVector
TFailedElementVector FailedSignalsVector
Definition: TrackUnit.h:794
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:411
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:881
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:967
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5895
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:20969
FNil
@ FNil
Definition: Utilities.h:43
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:587
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1565
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:947
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:788
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1555
TAllRoutes::RouteBackTruncateFlag
bool RouteBackTruncateFlag
used to flag the fact that a route is being truncated from the back in order to change the behaviour ...
Definition: TrackUnit.h:1730
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:847
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:7194
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:475
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1066
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1068
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:518
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:8027
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:19278
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:663
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:426
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7569
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:804
Erase
@ Erase
Definition: TrackUnit.h:67
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:851
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:402
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:484
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5516
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:828
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:831
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:878
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:595
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:14350
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:621
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:11836
Parapet
@ Parapet
Definition: TrackUnit.h:67
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:452
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:19427
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:115
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:805
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:1030
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:275
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:9358
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:19251
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:382
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:871
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:828
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:20290
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:610
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:952
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
< map of coupled continuations
Definition: TrackUnit.h:800
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:803
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:149
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:483
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:826
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:247
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:554
TRailGraphics::FSig72
Graphics::TBitmap * FSig72
Definition: GraphicUnit.h:922
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1071
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:740
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:818
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:16811
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:843
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:137
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:208
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:12056
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track display function, including direction markers.
Definition: TrackUnit.cpp:13154
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:509
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1323
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:501
TRailGraphics::FSig70
Graphics::TBitmap * FSig70
Definition: GraphicUnit.h:920
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:19214
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:616
TRailGraphics::FSig74
Graphics::TBitmap * FSig74
Definition: GraphicUnit.h:924
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:480
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:751
TTrack
Definition: TrackUnit.h:551
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1382
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:875
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1413
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:20438
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:287
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute, int StartPos) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:18169
TAllRoutes::LockedRouteRearTrackVectorPosition
unsigned int LockedRouteRearTrackVectorPosition
Definition: TrackUnit.h:1723
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1660
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8337
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:640
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:591
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:860
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:670
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:746
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:869
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:128
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:825
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:520
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:705
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:206
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:19930
TRailGraphics::FGSig74
Graphics::TBitmap * FGSig74
Definition: GraphicUnit.h:932
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:214
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:3037
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:455
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:10206
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:946
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6385
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:590
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:744
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:161
TTrackElement::TTrackElement
TTrackElement()
Constructor for non-specific default element. Use high neg numbers for 'unset' h & v as can go high n...
Definition: TrackUnit.h:167
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:864
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:808
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2638
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:204
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1658
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:7991
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:486
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:12942
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:13720
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:589
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1527
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:10835
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8726
IDInt
Definition: TrackUnit.h:500
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2605
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:593
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:20937
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:617
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:798
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4517
TDisplay
Definition: DisplayUnit.h:49
TRailGraphics::FGSig72
Graphics::TBitmap * FGSig72
Definition: GraphicUnit.h:930
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10585
TRailGraphics::FSig69
Graphics::TBitmap * FSig69
Definition: GraphicUnit.h:919
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:5259
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:147
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:872
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:792
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:841
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:443
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:21034
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1155
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9472
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:142
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:573
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:97
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7938
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1324
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:227
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:155
TTrackElement::Failed
bool Failed
New parameter added at v2.13.0 for failed points, signals & TSRs.
Definition: TrackUnit.h:141
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:906
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:14030
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:784
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:750
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:385
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:651
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:212
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:397
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:867
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:15156
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1728
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:130
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:787
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7906
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:635
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:828
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:801
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:735
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:149
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:910
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:774
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1538
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:858
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route (this will be truncated...
Definition: TrackUnit.h:1664
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:855
TOneRoute::RouteSearchLimitOneLeg
static const int RouteSearchLimitOneLeg
< limit to the total number of elements searched in attempting to find a route
Definition: TrackUnit.h:1551
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1674
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:441
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4811
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:590
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:9298
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:711
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:16517
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1352
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:736
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:437
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:14456
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:832
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1330
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:14231
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:153
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:722
Points
@ Points
Definition: TrackUnit.h:66
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:743
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:20003
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:873
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:10149
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:11907
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:414
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:602
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:840
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:503
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4224
Trail
@ Trail
Definition: TrackUnit.h:76
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:19163
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9531
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:781
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1899
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:502
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:39
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:824
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all signals appropriately. Also called when a new train is added a...
Definition: TrackUnit.cpp:18059
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:837
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:667
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:423
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:745
Continuation
@ Continuation
Definition: TrackUnit.h:66
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1062
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:36
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7785
GraphicUnit.h
PerfLogUnit.h
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3800
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:6151
TOnePrefDir::FindLinkingCompatiblePrefDir
bool FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that is compatible and links to another element at given vector number and l...
Definition: TrackUnit.cpp:14128
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:87
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:593
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:360
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9578
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:872
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:880
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:55
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:888
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:12985
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:579
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:842
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:772
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:877
TTrack::TInfrastructureFailureEntry::FailureTime
TDateTime FailureTime
Definition: TrackUnit.h:716
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:437
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:593
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1051
TTrack::FailedPointsVector
TFailedElementVector FailedPointsVector
Definition: TrackUnit.h:794
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3417
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:441
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:893
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1558
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:88
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:460
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:708
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:678
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:742
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1722
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:948
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:373
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:269
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:748
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:856
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:21116
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:491
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:13925
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1040
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:489
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:786
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1529
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1044
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:85
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:354
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:453
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:790
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:635
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:904
TRailGraphics::FGSig75
Graphics::TBitmap * FGSig75
Definition: GraphicUnit.h:933
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0),...
Definition: TrackUnit.cpp:4772
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:891
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:19901
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1755
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8864
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:718
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:699
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:596
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:812
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:672
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:11694
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:830
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:710
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1384
TOneRoute::SignalHasFailed
bool SignalHasFailed(int Caller)
Check incorporated in route search routines after have found a legitimate route, returns false for si...
Definition: TrackUnit.cpp:19305
TTrack::TInfrastructureFailureEntry::RepairTime
TDateTime RepairTime
Definition: TrackUnit.h:717
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:20953
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:583
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1909
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0), failed to false & clear Fa...
Definition: TrackUnit.cpp:4755
Connection
@ Connection
Definition: TrackUnit.h:76
TRailGraphics::FGSig73
Graphics::TBitmap * FGSig73
Definition: GraphicUnit.h:931
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3777
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:363
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:9812
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:1031
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:752
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:505
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:17872
TTrack::PopulateSimpleVector
void PopulateSimpleVector(int Caller)
clear then add all simple element track vector positions to the vector, added at v2....
Definition: TrackUnit.cpp:12214
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:12803
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:726
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:829
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8790
TTrack::RepairTSR
void RepairTSR(TFailedElementVector::iterator FPVIt)
remove TSR, added at v2.13.0
Definition: TrackUnit.cpp:12186
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:879
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1049
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:20212
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:20168
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:7267
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:568
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:11565
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:711
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:870
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:736
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1411
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:903
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:490
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
Definition: TrackUnit.cpp:18081
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5939
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:863
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:727
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:449
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:261
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
Definition: TrackUnit.h:155
TTrackElement::StationEntryStopLinkPos4
int StationEntryStopLinkPos4
Used for track at platforms ( 1 & 2) and non-station named locations (1 - 4) to mark the train front ...
Definition: TrackUnit.h:153
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:437
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:774
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:10272
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:575
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:738
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:752
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:19440
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4921
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:807
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2813
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:694
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7866
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:391
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3179
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:379
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:859
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:132
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:884
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:376
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:18030
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:631
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:77
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:14720
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:320
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:353
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:772
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:609
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:696
TUtilities::MaxRandomRepairTime
int MaxRandomRepairTime
Definition: Utilities.h:71
TPrefDirElement::GetRouteColour
int GetRouteColour(Graphics::TBitmap *EXG)
finds the route colour for a specific prefdir element with EXGraphicPtr EXG
Definition: TrackUnit.cpp:1108
TTrack::RepairFailedSignals
void RepairFailedSignals(TFailedElementVector::iterator FPVIt)
restore signal to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:12124
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:633
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:398
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:493
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1324
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:657
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:467
TRailGraphics::FSig73
Graphics::TBitmap * FSig73
Definition: GraphicUnit.h:923
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:667
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:936
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:644
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:12364
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:459
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:437
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:519
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:955
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:100
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1525
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:201
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8913
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:817
TDisplay::WarningLog
void WarningLog(int Caller, AnsiString Statement)
Display warning message Statement in the bottom left hand warning position and scroll other messages ...
Definition: DisplayUnit.cpp:522
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1807
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:9095
TUtilities::PointChangeEventsPerFailure
int PointChangeEventsPerFailure
number of points changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:93
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:645
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:591
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:726
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:14427
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:20921
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:143
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:613
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1381
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4435
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:818
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4646
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7729
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:2004
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:530
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1057
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6531
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:1028
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:714
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:66
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:844
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:646
TRailGraphics::FSig68
Graphics::TBitmap * FSig68
Definition: GraphicUnit.h:918
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7524
Platform
@ Platform
Definition: TrackUnit.h:66
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1413
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:214
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:669
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:889
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:782
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:707
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4671
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:792
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1668
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1064
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:784
TTrack::RepairFailedPoints
void RepairFailedPoints(TFailedElementVector::iterator FPVIt)
restore points to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:12156
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:958
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8288
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:684
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1337
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:814
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:849
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9729
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1038
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:773
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:11801
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1814
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:834
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:105
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:643
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1527
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:352
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:16938
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7712
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:822
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:151
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:799
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:697
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1529
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:618
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6548
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:728
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3677
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:776
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:662
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:586
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:806
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:758
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:11727
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:793
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:885
TTrack::ThisNonStationLongEnoughForSplit
bool ThisNonStationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int TrainLinkPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
as below but allow points & crossoverssee above under
Definition: TrackUnit.cpp:11346
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:17354
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:853
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:151
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: TrackUnit.h:41
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:683
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:949
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:306
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:713
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:627
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:732
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:83
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1074
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:417
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:586
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag = 1, top = 2, top rh diag = 3,...
Definition: TrackUnit.h:90
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:690
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:826
RouteCall
@ RouteCall
Definition: TrackUnit.h:1330
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:392
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
Definition: TrackUnit.h:155
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:12298
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:865
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TUtilities::DefaultTrackSpeedLimit
int DefaultTrackSpeedLimit
speed limit of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:91
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:611
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:506
NotSet
@ NotSet
Definition: TrackUnit.h:76
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:673
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:20484
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:89
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:268
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:395
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:612
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:599
TTrack::FailedSigTable
TSigElement FailedSigTable[8]
Definition: TrackUnit.h:745
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:11756
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:10667
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:678
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:533
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:204
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:795
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:951
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6449
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:161
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:67
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:959
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag, bool RecursiveCall)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:15861
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:750
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:12310
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1386
TAllRoutes::TLockedRouteClass::RearTrackVectorPosition
unsigned int RearTrackVectorPosition
the TrackVector position of the rearmost element selected for truncation (this will be truncated)
Definition: TrackUnit.h:1662
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:396
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:145
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1579
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:857
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:741
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:827
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:712
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:575
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:634
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10658
Bridge
@ Bridge
Definition: TrackUnit.h:66
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:868
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:444
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1324
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:816
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:528
Gap
@ Gap
Definition: TrackUnit.h:76
Buffers
@ Buffers
Definition: TrackUnit.h:66
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:17788
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:709
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:99
CrossConn
@ CrossConn
Definition: TrackUnit.h:76
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:12322
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:478
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4583
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:12245
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:852
TTrack::OneNonStationLongEnoughForSplit
bool OneNonStationLongEnoughForSplit(int Caller, AnsiString LocationName)
As below but here allow points & crossovers.
Definition: TrackUnit.cpp:11054
TTrack::ThisStationLongEnoughForSplit
bool ThisStationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneStationLongEnoughForSplit'.
Definition: TrackUnit.cpp:11217